1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots


plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, ...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf")) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_shape_discrete(name="") +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          title = element_text(size=14),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=12)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time


summarise_change <- function(model_data, model, population_denominator, grouping_var=NULL){

  #a. immediate change
  nd_immediate <- {{model_data}} %>%
    filter(year %in% c(1956:1957)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  immediate_change <- add_epred_draws({{model}},
                                      newdata=nd_immediate) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Immediate change") %>%
    ungroup()
  
  #b. post-ACF change
  nd_post <- {{model_data}} %>%
    filter(year %in% c(1956,1958)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  post_change <- add_epred_draws({{model}},
                                      newdata=nd_post) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Post-ACF change") %>%
    ungroup()
  
  #c. change in slope post vs. pre-ACF
  slope_change <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{grouping_var}}) %>%
    filter(year!=1957) %>%
    add_epred_draws({{model}}) %>%
    mutate(inc_100k = .epred/{{population_denominator}}*100000) %>%
    group_by(year, {{grouping_var}}, acf_period, ) %>%
    mean_qi(inc_100k) %>%
    ungroup() %>%
    mutate(n_years = length(year), .by=c(acf_period, {{grouping_var}})) %>%
    summarise(pct_change_epred_overall = (((last(inc_100k) - first(inc_100k))/first(inc_100k))),
              pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
              pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
      
              pct_change_epred_annual = (((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years),
              pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
              pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
              .by = c(acf_period, {{grouping_var}})) %>%
    distinct() %>%
    mutate(change = "Slope change")

  lst(immediate_change, post_change, slope_change)
    
}

Function for calculating difference from counterfactual

calcuate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf)
  
  #Calcuate incidence per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred)  %>%
      group_by(.draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotlan with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))
Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey(base_family = "Segoe UI") +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold"))) +
  scalebar(glasgow_wards_1951, dist = 2, dist_unit = "km",
             transform = TRUE, model = "WGS84", location="bottomleft")

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.51 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB incidence

5.1 Overall TB incidence

Now calculate incidence per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

7. Overall pulmonary TB model

7.1 FIt the model and priors

First model will investigate the impact of mass miniature X-ray campaign on pulmonary TB case notification rate using an interrupted time series analysis.

Set up the data


mdata1 <- overall_inc %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(y_num = 1:nrow(.)) %>%
  rename(extrapulmonary_notifications = `non-pulmonary_notifications`)

Work on the priors a bit

Basic prior


basic_prior <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.25), class = b))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata1$pulmonary_notifications)
[1] 1858.429
#variance of counts per year
var(mdata1$pulmonary_notifications)
[1] 716579.8

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Slightly more informative prior (“weakly informative” really)

Fit a model with only priors

Now fit the model with the weakly informative priors

pp_check(m_pulmonary_overall, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

7.2 Summarise change in CNRs

Summarise the posterior

Make this into a figure

ggsave(here("figures/f1.png"))
Saving 7 x 7 in image

Summary of change in notifications

summarise_change(model_data=mdata1, model=m_pulmonary_overall, population_denominator=total_population, grouping_var=NULL) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

(Alternative way - keep in for now)


overall_immediate_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1957)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_immediate = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()

overall_post_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1958)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_post = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()


overall_slope_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1950, 1956, 1958, 1963)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  group_by(acf_period, .draw) %>%
  summarise(pct_change_slope = ((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years) %>%
  distinct() %>%
  pivot_wider(names_from = c(acf_period),
              values_from = pct_change_slope) %>%
  mutate(ratio_annual_slope = `c. post-acf` / `a. pre-acf`)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'acf_period', '.draw'. You can override using the `.groups` argument.

Correlation between immediate effect and post effect of ACF


left_join(overall_immediate_draws, overall_post_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=pct_change_post)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  stat_regline_equation(label.x = 0.25, label.y = -0.25, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(labels = percent,
                     breaks = pretty_breaks(n = 5)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Boundaries are posterior desnity intervals from 4000 draws") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

Correlation between immediate effect and change in slope


left_join(overall_immediate_draws, overall_slope_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  #stat_regline_equation(label.x = 0.25, label.y = 0.02, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(breaks = pretty_breaks(n = 5),
                     limits = c(0, 10)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Points are draws from posteior distribution") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

7.3 Compared to counterfactual


overall_pulmonary_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_pulmonary_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(c(pct_change:pct_change.upper), percent, accuracy = 0.1)`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function instead.

  # Previously
  across(a:b, mean, na.rm = TRUE)

  # Now
  across(a:b, \(x) mean(x, na.rm = TRUE))
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Total pulmonary TB cases averted between 1958 and 1963

8. Extra-pulmonary TB notifications

8.1 Fit the model

plot_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population, outcome=inc_ep_100k)
  
ggsave(here("figures/s6.png"), width=10)
Saving 10 x 4.51 in image

8.2 Summary of change

A. Percentage change in mortality, from 1956 to 1957 (i.e. immediate ACF effect)


summarise_change(model_data=mdata1, model = m_extrap_overall, population_denominator = total_population) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

8.3 Compared to counterfactual


overall_ep_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extra pulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

9. Ward level model

9.1 Fit the model


mdata2 <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

(Note the denominator without institutionalised people and “shipping”!)

Now fit the model with data

pp_check(m_pulmonary_ward, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

9.2 Summary of change

A. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

ward_change %>%
  map(datatable)
$immediate_change

$post_change

$slope_change
NA

As a supplementary figure

ggsave(here("figures/s5.png"))
Saving 7 x 7 in image
ggsave(here("figures/s6.png"))
Saving 7 x 7 in image

percentage change = (final value - initial value) / initial value

(Alternative figure - keep in for the minute)

Is there any correlation between immediate increase and a) post-intervention (1958) effect, and b) post intervention slope (1958-1963)


ward_cors <- ward_impact_out %>%
  select(ward, immediate_effect = acf_inc100k_rr,
               immediate_effect_lower = acf_inc100k_rr.lower,
               immediate_effect_upper = acf_inc100k_rr.upper) %>%
  right_join(
    ward_pulm_impact2 %>% 
      select(ward, post_effect = acf_inc100k_rr,
               post_effect_lower = acf_inc100k_rr.lower,
               post_effect_upper = acf_inc100k_rr.upper)
  ) %>%
  right_join(
    ward_pulm_impact3 %>%
      filter(acf_period=="c. post-acf") %>%
      select(ward, slope_effect = pct_change_epred_annual,
             slope_effect_lower = pct_change_lower_annual,
             slope_effect_upper = pct_change_upper_annual)
  )
Error in select(., ward, immediate_effect = acf_inc100k_rr, immediate_effect_lower = acf_inc100k_rr.lower,  : 
  object 'ward_impact_out' not found

Try a different way with the full distribution of posteriors

ward_immediate_draws <- mdata2 %>%
  select(year, year2, y_num, acf_period, population_without_inst_ship, cases, ward) %>%
  filter(year %in% c(1956,1957)) %>%
  add_epred_draws(m_pulmonary_ward) %>%
  mutate(inc_100k = .epred/population_without_inst_ship*100000) %>%
  group_by(ward, .draw) %>%
  summarise(pct_change_immediate = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  arrange(ward) %>%
  ungroup()
`summarise()` has grouped output by 'ward'. You can override using the `.groups` argument.

Correlation between immediate effect and post effect of ACF


# 
# left_join(ward_immediate_draws, ward_post_draws) %>%
#   ggplot(aes(x=pct_change_immediate, y=pct_change_post, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 0, label.y = 0.25, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(labels = percent) +
#   labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
#        y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        caption="Points are draws from posteior distribution") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(ward~.)

Correlation between immediate effect and change in slope


# left_join(ward_immediate_draws, ward_slope_draws) %>%
#   ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   #stat_regline_equation(label.x = 0, label.y = 0.02, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(limits = c(0, 10)) +
#   labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
#        y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        caption="Points are draws from posteior distribution") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(ward~.)

Join these together with the overall estimates to make a single figure for showing impact


# f2_data <- 
#   left_join(overall_immediate_draws, overall_post_draws) %>%
#   left_join(overall_slope_draws) %>%
#   mutate(level = "overall",
#          ward = "Glasgow") %>%
#   bind_rows(
#     left_join(ward_immediate_draws, ward_post_draws) %>%
#   left_join(ward_slope_draws) %>%
#   mutate(level = "ward")
#   )
# 
# f2a <- f2_data %>% 
#   ggplot(aes(x=pct_change_immediate, y=pct_change_post, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 0, label.y = 0.12, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability density") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(labels = percent) +
#   labs(y="Post-intervention impact: Percentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(fct_relevel(ward,
#                          "Glasgow",
#                          after=0)~., ncol = 5) + 
#   guides(colour = guide_legend(override.aes = list(size=4)))
# 
# f2a
# 
# f2b <- f2_data %>% 
#   ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 1.2, label.y = 12, size=4) +
#   scale_x_continuous(labels = percent,
#                      breaks = pretty_breaks(n = 4)) +
#   scale_y_continuous(breaks = pretty_breaks(n = 4),
#                 limits = c(0,15)) +
#   scale_fill_viridis_d(option="E") +
#   labs(y="Post-intervention impact: Relative change in annual CNR slope (1958-1963 vs. 1950-1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        colour="Posterior probability density") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(fct_relevel(ward,
#                          "Glasgow",
#                          after=0)~., ncol = 5) + 
#   guides(colour = guide_legend(override.aes = list(size=4)))
# 
# f2b
# 
# (f2a / f2b) + plot_annotation(tag_levels = 'A')

ggsave(here("figures/f2.png"), height=18, width=10)

9.3 Compared to counterfactual

ward_counterf %>%
  map(datatable)
$counter_post

$counter_post_overall
NA

Total pulmonary TB cases averted between 1958 and 1963

Add the numbers averted for each ward to the figure

10. Age-sex model

10.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata3 <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

winform_prior3 <- c(prior(normal(0, 1), class = Intercept),
                  #prior(gamma(0.5, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))


m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata3,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  backend = "cmdstanr")
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpkkDov4/model-ee93156594b9.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

-
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]

\
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
1 warning generated.

-

\

|
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

/

-

\

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 finished in 9.1 seconds.
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 9.4 seconds.
Chain 3 finished in 9.2 seconds.
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 9.3 seconds.

All 4 chains finished successfully.
Mean chain execution time: 9.3 seconds.
Total execution time: 9.7 seconds.
summary(m_age_sex)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + (acf_period) * (age * sex) + (acf_period:y_num) * (age * sex) 
   Data: mdata3 (Number of observations: 224) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                                    4.47      0.08     4.31     4.62 1.00     2429     2931
y_num                                       -0.18      0.02    -0.22    -0.13 1.00     1390     2194
acf_periodb.acf                             -0.01      0.25    -0.49     0.47 1.00    10433     2887
acf_periodc.postMacf                         0.01      0.15    -0.30     0.30 1.00     4606     3010
age06_15                                     0.41      0.12     0.18     0.65 1.00     3070     2827
age16_25                                     1.56      0.11     1.34     1.79 1.00     2070     2939
age26_35                                     0.92      0.11     0.70     1.14 1.00     2537     2963
age36_45                                     0.24      0.12     0.02     0.47 1.00     3037     3317
age46_55                                    -0.34      0.13    -0.59    -0.08 1.00     2813     2851
age56_65                                    -0.64      0.13    -0.90    -0.38 1.00     3571     3404
age65P                                      -0.99      0.14    -1.26    -0.71 1.00     3427     2876
sexM                                         0.20      0.09     0.03     0.37 1.00     2440     2716
age06_15:sexM                               -0.29      0.15    -0.58     0.01 1.00     3885     3215
age16_25:sexM                               -0.31      0.14    -0.58    -0.03 1.00     2987     3222
age26_35:sexM                               -0.18      0.14    -0.45     0.09 1.00     2928     2855
age36_45:sexM                                0.16      0.14    -0.12     0.44 1.00     3311     3278
age46_55:sexM                                0.69      0.15     0.38     0.99 1.00     2993     2969
age56_65:sexM                                0.53      0.16     0.23     0.84 1.00     3329     3430
age65P:sexM                                  0.25      0.16    -0.06     0.56 1.00     3310     3450
acf_periodb.acf:age06_15                     0.02      0.25    -0.47     0.53 1.00     8378     2757
acf_periodc.postMacf:age06_15               -0.37      0.22    -0.81     0.08 1.00     6912     2822
acf_periodb.acf:age16_25                     0.03      0.25    -0.47     0.52 1.00     8484     2916
acf_periodc.postMacf:age16_25                0.23      0.20    -0.16     0.61 1.00     6331     3214
acf_periodb.acf:age26_35                     0.04      0.24    -0.44     0.52 1.00     9149     2749
acf_periodc.postMacf:age26_35                0.14      0.20    -0.26     0.54 1.00     6922     3253
acf_periodb.acf:age36_45                     0.05      0.25    -0.44     0.55 1.00     8346     3264
acf_periodc.postMacf:age36_45                0.10      0.20    -0.29     0.50 1.00     7240     3137
acf_periodb.acf:age46_55                     0.05      0.25    -0.44     0.54 1.00     8134     2763
acf_periodc.postMacf:age46_55                0.20      0.21    -0.20     0.59 1.00     5967     3717
acf_periodb.acf:age56_65                     0.04      0.24    -0.45     0.52 1.00     7812     2763
acf_periodc.postMacf:age56_65                0.05      0.21    -0.37     0.46 1.00     6009     2943
acf_periodb.acf:age65P                       0.04      0.25    -0.44     0.53 1.00     8029     3377
acf_periodc.postMacf:age65P                  0.11      0.22    -0.31     0.55 1.00     6647     3257
acf_periodb.acf:sexM                        -0.01      0.24    -0.47     0.45 1.00     9693     2911
acf_periodc.postMacf:sexM                    0.17      0.17    -0.18     0.51 1.00     5883     3083
y_num:acf_periodb.acf                       -0.06      0.05    -0.15     0.03 1.00     2624     2474
y_num:acf_periodc.postMacf                   0.00      0.03    -0.05     0.05 1.00     1687     2704
acf_periodb.acf:age06_15:sexM                0.01      0.24    -0.48     0.48 1.00     7743     2919
acf_periodc.postMacf:age06_15:sexM          -0.27      0.23    -0.72     0.18 1.00     8217     3108
acf_periodb.acf:age16_25:sexM                0.01      0.24    -0.47     0.48 1.00     8818     2623
acf_periodc.postMacf:age16_25:sexM           0.12      0.23    -0.32     0.58 1.00     7353     3074
acf_periodb.acf:age26_35:sexM                0.01      0.25    -0.49     0.50 1.00     9256     2639
acf_periodc.postMacf:age26_35:sexM           0.05      0.22    -0.39     0.50 1.00     7281     2607
acf_periodb.acf:age36_45:sexM                0.00      0.25    -0.49     0.48 1.00     8703     3032
acf_periodc.postMacf:age36_45:sexM           0.01      0.22    -0.43     0.45 1.00     7249     2773
acf_periodb.acf:age46_55:sexM                0.01      0.24    -0.47     0.49 1.00     9103     2587
acf_periodc.postMacf:age46_55:sexM           0.22      0.22    -0.21     0.65 1.00     6530     3109
acf_periodb.acf:age56_65:sexM                0.02      0.25    -0.47     0.53 1.00     9465     2697
acf_periodc.postMacf:age56_65:sexM           0.10      0.22    -0.33     0.53 1.00     7499     2951
acf_periodb.acf:age65P:sexM                  0.02      0.25    -0.46     0.50 1.00     9198     3071
acf_periodc.postMacf:age65P:sexM             0.12      0.23    -0.32     0.55 1.01     7371     2487
y_num:acf_perioda.preMacf:age06_15           0.06      0.03     0.00     0.13 1.00     1906     2589
y_num:acf_periodb.acf:age06_15               0.14      0.05     0.04     0.24 1.00     2804     2660
y_num:acf_periodc.postMacf:age06_15          0.08      0.02     0.03     0.12 1.00     4267     3359
y_num:acf_perioda.preMacf:age16_25           0.18      0.03     0.12     0.24 1.00     1422     2399
y_num:acf_periodb.acf:age16_25               0.25      0.05     0.15     0.34 1.00     2590     2847
y_num:acf_periodc.postMacf:age16_25          0.03      0.02    -0.02     0.07 1.00     3339     2925
y_num:acf_perioda.preMacf:age26_35           0.19      0.03     0.13     0.25 1.00     1637     2735
y_num:acf_periodb.acf:age26_35               0.30      0.05     0.21     0.40 1.00     2660     3000
y_num:acf_periodc.postMacf:age26_35          0.08      0.02     0.04     0.13 1.00     3778     3384
y_num:acf_perioda.preMacf:age36_45           0.17      0.03     0.11     0.23 1.00     1912     2636
y_num:acf_periodb.acf:age36_45               0.37      0.05     0.27     0.47 1.00     2570     2892
y_num:acf_periodc.postMacf:age36_45          0.12      0.02     0.07     0.16 1.00     3471     3230
y_num:acf_perioda.preMacf:age46_55           0.13      0.03     0.07     0.20 1.00     2070     2746
y_num:acf_periodb.acf:age46_55               0.37      0.05     0.27     0.47 1.00     2640     3015
y_num:acf_periodc.postMacf:age46_55          0.12      0.02     0.08     0.17 1.00     3329     3026
y_num:acf_perioda.preMacf:age56_65           0.09      0.04     0.01     0.16 1.00     2557     2631
y_num:acf_periodb.acf:age56_65               0.30      0.05     0.20     0.40 1.00     2875     2937
y_num:acf_periodc.postMacf:age56_65          0.12      0.02     0.07     0.17 1.00     3806     3521
y_num:acf_perioda.preMacf:age65P             0.10      0.04     0.02     0.17 1.00     2323     2883
y_num:acf_periodb.acf:age65P                 0.31      0.05     0.21     0.42 1.00     2557     2529
y_num:acf_periodc.postMacf:age65P            0.12      0.02     0.08     0.17 1.00     3806     3486
y_num:acf_perioda.preMacf:sexM               0.00      0.03    -0.05     0.06 1.00     1427     2161
y_num:acf_periodb.acf:sexM                  -0.06      0.06    -0.17     0.05 1.00     1911     2495
y_num:acf_periodc.postMacf:sexM             -0.04      0.02    -0.08     0.01 1.00     2451     2376
y_num:acf_perioda.preMacf:age06_15:sexM     -0.03      0.04    -0.11     0.06 1.00     2333     2818
y_num:acf_periodb.acf:age06_15:sexM          0.04      0.06    -0.08     0.17 1.00     2246     2948
y_num:acf_periodc.postMacf:age06_15:sexM     0.06      0.03     0.00     0.12 1.00     3715     2984
y_num:acf_perioda.preMacf:age16_25:sexM     -0.05      0.04    -0.13     0.02 1.00     1797     2555
y_num:acf_periodb.acf:age16_25:sexM          0.04      0.06    -0.07     0.16 1.00     2165     2572
y_num:acf_periodc.postMacf:age16_25:sexM     0.01      0.03    -0.04     0.07 1.00     2953     3168
y_num:acf_perioda.preMacf:age26_35:sexM     -0.04      0.04    -0.11     0.04 1.00     1870     2546
y_num:acf_periodb.acf:age26_35:sexM          0.05      0.06    -0.07     0.17 1.00     2149     2476
y_num:acf_periodc.postMacf:age26_35:sexM     0.01      0.03    -0.04     0.07 1.00     3056     2807
y_num:acf_perioda.preMacf:age36_45:sexM      0.00      0.04    -0.07     0.08 1.00     2046     2557
y_num:acf_periodb.acf:age36_45:sexM          0.03      0.06    -0.09     0.15 1.00     2159     2970
y_num:acf_periodc.postMacf:age36_45:sexM     0.01      0.03    -0.04     0.07 1.00     3192     2893
y_num:acf_perioda.preMacf:age46_55:sexM      0.09      0.04     0.00     0.17 1.00     2176     2834
y_num:acf_periodb.acf:age46_55:sexM          0.07      0.06    -0.04     0.19 1.00     2182     2850
y_num:acf_periodc.postMacf:age46_55:sexM     0.01      0.03    -0.04     0.07 1.00     2864     2889
y_num:acf_perioda.preMacf:age56_65:sexM      0.17      0.04     0.09     0.26 1.00     2469     2962
y_num:acf_periodb.acf:age56_65:sexM          0.16      0.06     0.04     0.28 1.00     2273     3150
y_num:acf_periodc.postMacf:age56_65:sexM     0.09      0.03     0.04     0.15 1.00     3443     3481
y_num:acf_perioda.preMacf:age65P:sexM        0.15      0.05     0.07     0.24 1.00     2348     3140
y_num:acf_periodb.acf:age65P:sexM            0.19      0.06     0.07     0.31 1.00     2208     2439
y_num:acf_periodc.postMacf:age65P:sexM       0.09      0.03     0.03     0.15 1.00     2998     3054

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    98.38     33.81    52.32   180.75 1.00     1401     2192

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_age_sex)

pp_check(m_age_sex, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

Summarise posterior

ggsave(here("figures/s7.png"), height=10)
Saving 7 x 10 in image

10.2 Summary of impact of intervention

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

nd <- mdata3 %>%
  filter(year %in% c(1956:1957)) %>%
  select(acf_period, y_num, age, sex)


age_sex_impact_out <- 
  add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
         post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `b. acf`)`.
age_sex_impact_out %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
  
f3a <- age_sex_impact_out %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
  
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)

nd <- mdata3 %>%
  filter(year %in% c(1956,1958)) %>%
  select(acf_period, y_num, age, sex)

#Do it with calculating incidence, then sumamrising.
age_sex_impact2 <-add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
        post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `c. post-acf`)`.
age_sex_impact2 %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
f3b <- age_sex_impact2 %>%  
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

10.3 Compared to counterfactual

counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 
Joining with `by = join_by(age, sex, .draw)`

Join together for Figure 2.

ggsave(here("figures/f3.png"), width = 12)
Saving 12 x 7 in image

11. Division-level model

(Very much a work in progress!)

10.2 Summary of impact


summarise_change(model_data=mdata4, model = m_pulmonary_division, population_denominator = population_without_inst_ship, grouping_var = division) %>%
  map(datatable)

12. Counterfactual table

Make a table of counterfactual effects for the manuscript


pulmonary_counterfactuals <- tidy_counterfactuals(overall_pulmonary_counterf$counter_post)
pulmonary_counterfactuals_overall <- tidy_counterfactuals_overall(overall_pulmonary_counterf$counter_post_overall)

extrapulmonary_counterfactuals <- tidy_counterfactuals(overall_ep_counterf$counter_post)
extrapulmonary_counterfactuals_overall <- tidy_counterfactuals_overall(overall_ep_counterf$counter_post_overall)

age_sex_counterfactuals_overall <- tidy_counterfactuals_overall(counter_post_overall_age_sex) %>% mutate(model = "Age-sex")

bind_rows(
  bind_rows(pulmonary_counterfactuals, pulmonary_counterfactuals_overall) %>% mutate(model = "Pulmonary TB", sex=NA, age=NA),
  bind_rows(extrapulmonary_counterfactuals, extrapulmonary_counterfactuals_overall) %>% mutate(model = "Extra-pulmonary TB", sex=NA, age=NA),
  age_sex_counterfactuals_overall) %>%
  select(model, year, age, sex, diff_inc, rr_inc, cases_averted, pct_change)

#experimental below here #############

What about a multilevel model with Wards nested within divisions?

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3NuKQoKYGBgCgojIyMjIDEuMiBIZWxwZXIgZnVuY3Rpb25zCgpGdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSB0aHJvdWdob3V0IHRoZSBzY3JpcHQKCmBgYHtyfQojbGFiZWxsZXIgZm9yIHllYXJzCnllYXJfbGFiZWxzIDwtIGMoMTk1MDoxOTYzKQoKI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCmFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCmFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKCmBgYAoKRnVuY3Rpb24gZm9yIGNvdW50ZXJmYWN0dWFsIHBsb3RzCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwgPC0gZnVuY3Rpb24obW9kZWxfZGF0YSwgbW9kZWwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IsIG91dGNvbWUsIGdyb3VwaW5nX3Zhcj1OVUxMLCAuLi4pewogIAogICNsYWJlbGxlciBmb3IgeWVhcnMKICB5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiAgI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKICAjU2VnbWVudCBmb3IgZ3JhcGhzIHRvIG1hdGNoIEFDRiBwZXJpb2QKICBhY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQogIGFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKICBzdW1tYXJ5IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7b3V0Y29tZX19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgICAuZXByZWRfaW5jLmxvd2VyID0gLmVwcmVkLmxvd2VyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAlPiUKICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCgoKICAjY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQogIAogIGNvdW50ZXJmYWN0IDwtCiAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCB7e291dGNvbWV9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgZ3VpZGVzKHNoYXBlPSJub25lIikKCiAgICBmYWNldF92YXJzIDwtIHZhcnMoLi4uKQoKICBpZiAobGVuZ3RoKGZhY2V0X3ZhcnMpICE9IDApIHsKICAgIHAgPC0gcCArIGZhY2V0X3dyYXAoZmFjZXRfdmFycykKICB9CiAgcAoKfQoKYGBgCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgIG1lYXN1cmVzIG9mIGNoYW5nZSBvdmVyIHRpbWUKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZSA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewoKICAjYS4gaW1tZWRpYXRlIGNoYW5nZQogIG5kX2ltbWVkaWF0ZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICAgIHNlbGVjdChhY2ZfcGVyaW9kLCB5ZWFyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pCgogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIGltbWVkaWF0ZV9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX2ltbWVkaWF0ZSkgJT4lCiAgICBtdXRhdGUoZXByZWRfaW5jMTAwayA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSkgJT4lCiAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtdXRhdGUoYWNmX2luYzEwMGtfZGlmZiA9IGxhc3QoZXByZWRfaW5jMTAwayktZmlyc3QoZXByZWRfaW5jMTAwayksCiAgICAgICAgICAgYWNmX2luYzEwMGtfcnIgPSBsYXN0KGVwcmVkX2luYzEwMGspL2ZpcnN0KGVwcmVkX2luYzEwMGspKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShhY2ZfaW5jMTAwa19kaWZmLCBhY2ZfaW5jMTAwa19ycikgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIkltbWVkaWF0ZSBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNiLiBwb3N0LUFDRiBjaGFuZ2UKICBuZF9wb3N0IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogICAgc2VsZWN0KGFjZl9wZXJpb2QsIHllYXIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkKCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX3Bvc3QpICU+JQogICAgbXV0YXRlKGVwcmVkX2luYzEwMGsgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0pICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbXV0YXRlKGFjZl9pbmMxMDBrX2RpZmYgPSBsYXN0KGVwcmVkX2luYzEwMGspLWZpcnN0KGVwcmVkX2luYzEwMGspLAogICAgICAgICAgIGFjZl9pbmMxMDBrX3JyID0gbGFzdChlcHJlZF9pbmMxMDBrKS9maXJzdChlcHJlZF9pbmMxMDBrKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoYWNmX2luYzEwMGtfZGlmZiwgYWNmX2luYzEwMGtfcnIpICU+JQogICAgbXV0YXRlKGNoYW5nZSA9ICJQb3N0LUFDRiBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNjLiBjaGFuZ2UgaW4gc2xvcGUgcG9zdCB2cy4gcHJlLUFDRgogIHNsb3BlX2NoYW5nZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kLCApICU+JQogICAgbWVhbl9xaShpbmNfMTAwaykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWMoYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkpICU+JQogICAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpKSwKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgICAKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpL25feWVhcnMpLAogICAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9hbm51YWwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pKSAlPiUKICAgIGRpc3RpbmN0KCkgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIlNsb3BlIGNoYW5nZSIpCgogIGxzdChpbW1lZGlhdGVfY2hhbmdlLCBwb3N0X2NoYW5nZSwgc2xvcGVfY2hhbmdlKQogICAgCn0KCmBgYAoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQpjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewogIAogICNlZmZlY3QgdnMuIGNvdW50ZXJmYWN0dWFsCiAgY291bnRlcmZhY3QgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jX2NvdW50ZXJmID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwgLmVwcmVkX2NvdW50ZXJmPS5lcHJlZCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIC5kcmF3LCAuZXByZWRfY291bnRlcmYsIC5lcHJlZF9pbmNfY291bnRlcmYpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpICU+JQogICAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCAuZHJhdywgLmVwcmVkLCAuZXByZWRfaW5jKSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZAogICAgY291bnRlcmZhY3Rfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAlPiUKICAgICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkpICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKY291bnRlcl9wb3N0IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0LCBwb3N0X2NoYW5nZSkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZiwKICAgICAgICAgICBkaWZmX2luYzEwMGsgPSAuZXByZWRfaW5jIC0gLmVwcmVkX2luY19jb3VudGVyZiwKICAgICAgICAgICBycl9pbmMxMDBrID0gLmVwcmVkX2luYy8uZXByZWRfaW5jX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlLCBkaWZmX2luYzEwMGssIHJyX2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsLCBwb3N0X2NoYW5nZV9vdmVyYWxsKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCmxzdChjb3VudGVyX3Bvc3QsIGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKfQoKCgpgYGAKCkZ1bmN0aW9uIGZvciB0aWR5aW5nIHVwIGNvdW50ZXJmYWN0dWFscyAobW9zdGx5IGZvciBtYWtpbmcgbmljZSB0YWJsZXMpCgpgYGB7cn0KCnRpZHlfY291bnRlcmZhY3R1YWxzIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIiksCiAgICAgICAgICAgIGRpZmZfaW5jID0gZ2x1ZTo6Z2x1ZSgie2RpZmZfaW5jMTAwa30gKHtkaWZmX2luYzEwMGsubG93ZXJ9IHRvIHtkaWZmX2luYzEwMGsudXBwZXJ9KSIpLAogICAgICAgICAgICBycl9pbmMgPSBnbHVlOjpnbHVlKCJ7cnJfaW5jMTAwa30gKHtycl9pbmMxMDBrLmxvd2VyfSB0byB7cnJfaW5jMTAway51cHBlcn0pIikpCn0KCgp0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSkKfQoKYGBgCgoKCiMjIyAyLiBEYXRhCgpJbXBvcnQgZGF0YXNldHMgZm9yIGFuYWx5c2lzCgojIyMjIDIuMSBTaGFwZWZpbGVzCgpNYWtlIGEgbWFwIG9mIEdsYXNnb3cgd2FyZHMKCmBgYHtyfQoKZ2xhc2dvd193YXJkc18xOTUxIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9nbGFzZ293X3dhcmRzXzE5NTEuZ2VvanNvbiIpKQoKYGBgCgpgYGB7cn0KCiNyZWFkIGluIFNjb3RsYW5kIGJvdW5kYXJ5CnNjb3RsYW5kIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9TY290bGFuZF9ib3VuZGFyeS9TY290bGFuZCBib3VuZGFyeS5zaHAiKSkKCgoKI21ha2UgYSBib3VuZGluZyBib3ggZm9yIEdsYXNnb3cKYmJveCA8LSBzdF9iYm94KGdsYXNnb3dfd2FyZHNfMTk1MSkgfD4gc3RfYXNfc2ZjKCkKCiNwbG90IHNjb3RsYW4gd2l0aCBhIGJvdW5kaW5nIGJveCBhcm91bmQgdGhlIENpdHkgb2YgR2xhc2dvdwpzY290bGFuZF93aXRoX2Jib3ggPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHNjb3RsYW5kLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgZ2VvbV9zZihkYXRhID0gYmJveCwgY29sb3VyID0gIiNDNjBDMzAiLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQUY3RkEiLCBzaXplID0gMC4zKSkKCgojcGxvdCB0aGUgd2FyZHMKI25vdGUgd2UgdGlkeSB1cCBzb21lIG5hbWVzIHRvIGZpdCBvbiBtYXAKZ2xhc2dvd193YXJkX21hcCA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKHdhcmQgPSBjYXNlX3doZW4od2FyZD09IlNoZXR0bGVzdG9uIGFuZCBUb2xsY3Jvc3MiIH4gIlNoZXR0bGVzdG9uIGFuZFxuVG9sbGNyb3NzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoV2VzdCkiIH4gIlBhcnRpY2tcbihXZXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKEVhc3QpIiB+ICJQYXJ0aWNrXG4oRWFzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJOb3J0aCBLZWx2aW4iIH4gIk5vcnRoXG5LZWx2aW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJLaW5uaW5nIFBhcmsiIH4gIktpbm5pbmdcblBhcmsiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkKSkgJT4lCiAgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9ZGl2aXNpb24pKSArCiAgZ2VvbV9zZl9sYWJlbChhZXMobGFiZWwgPSB3YXJkKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siLCBmYW1pbHkgPSAiU2Vnb2UgVUkiKSArCiAgI3NjYWxlX2NvbG91cl9pZGVudGl0eSgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJDaXR5IG9mIEdsYXNnb3cgRGl2aXNpb24iKSArCiAgdGhlbWVfZ3JleShiYXNlX2ZhbWlseSA9ICJTZWdvZSBVSSIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSIiLAogICAgICAgZmlsbD0iRGl2aXNpb24iKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLCBzaXplID0gMC4zKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk3OCIpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41LCB0aXRsZS50aGVtZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpKSArCiAgc2NhbGViYXIoZ2xhc2dvd193YXJkc18xOTUxLCBkaXN0ID0gMiwgZGlzdF91bml0ID0gImttIiwKICAgICAgICAgICAgIHRyYW5zZm9ybSA9IFRSVUUsIG1vZGVsID0gIldHUzg0IiwgbG9jYXRpb249ImJvdHRvbWxlZnQiKQoKI2FkZCB0aGUgbWFwIG9mIHNjb3RsYW5kIGFzIGFuIGluc2V0CmdsYXNnb3dfd2FyZF9tYXAgKyBpbnNldF9lbGVtZW50KHNjb3RsYW5kX3dpdGhfYmJveCwgMC43NSwgMCwgMSwgMC40KQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczEucG5nIiksIGhlaWdodD0xMCwgd2lkdGggPSAxMikKCgpgYGAKCgoKIyMjIDMuIERlbm9taW5hdG9ycwoKTG9hZCBpbiB0aGUgZGF0YXNldHMgZm9yIGRlbm9ub21pYXRvcnMsIGFuZCBjaGVjayBmb3IgY29uc2lzdGVuY3kuCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJvdmVyYWxsX3BvcHVsYXRpb24iKQoKb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50Cm92ZXJhbGxfcG9wcyA8LSBvdmVyYWxsX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKCk5vdGUsIHdlIGhhdmUgdGhyZWUgcG9wdWxhdGlvbiBlc3RpbWF0ZXM6CgoxLiBQb3B1bGF0aW9uIHdpdGhvdXQgaW5zdGl0dXRpb25hbGlzZWQgcGVvcGxlIG9yIHBlb3BsZSBpbiBzaGlwcGluZwoyLiBQb3B1bGF0aW9uIGluIGluc3RpdHV0aW9ucwozLiBQb3B1bGF0aW9uIGluIHNoaXBwaW5nCgooUG9wdWxhdGlvbiBpbiBzaGlwcGluZyBpcyBlc3RpbWF0ZWQgZnJvbSB0aGUgMTk1MSBjZW5zdXMsIHNvIGlzIHRoZSBzYW1lIGZvciBtb3N0IHllYXJzKQoKIyMjIyAzLjEgT3ZlcmFsbCBwb3B1bGF0aW9uCgpGaXJzdCwgcGxvdCB0aGUgdG90YWwgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iLCBmaWxsPSJtZWRpdW1zZWFncmVlbiIpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIpLCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHRvdGFsIHBvcHVsYXRpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpCgoKYGBgCgpOb3cgdGhlIHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyBwb3B1bGF0aW9uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHg9eWVhcjIpLCBhbHBoYT0wLjUsIGNvbG91ciA9ICJwdXJwbGUiLCBmaWxsPSJwdXJwbGUiKSArCiAgZ2VvbV9wb2ludChhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgY29sb3VyID0gInB1cnBsZSIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogcG9wdWxhdGlvbiBleGNsdWRpbmcgaW5zdGl0dXRpb25hbGlzZWQgYW5kIHNoaXBwaW5nIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKIyMjIyAzLjIgUG9wdWxhdGlvbiBieSBXYXJkCgpUaGVyZSBhcmUgNSBEaXZpc2lvbnMgY29udGFpbmluZyAzNyBXYXJkcyBpbiB0aGUgR2xhc2dvdyBDb3Jwb3JhdGlvbiwgd2l0aCBjb25zaXN0ZW50IGJvdW5kYXJpZXMgb3ZlciB0aW1lLgoKYGBge3J9CiNsb29rLXVwIHRhYmxlIGZvciBkaXZpc2lvbnMgYW5kIHdhcmRzCndhcmRfbG9va3VwIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImRpdmlzaW9uc193YXJkcyIpCgoKd2FyZF9wb3BzIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gIndhcmRfcG9wdWxhdGlvbiIpCgp3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKd2FyZF9wb3BzIDwtIHdhcmRfcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCiNHZXQgdGhlIERpdmlzaW9uIHBvcHVsYXRpb24KZGl2aXNpb25fcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24sIHllYXIpICU+JQogIHN1bW1hcmlzZShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwID0gc3VtKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGluc3RpdHV0aW9ucyA9IHN1bShpbnN0aXR1dGlvbnMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHNoaXBwaW5nID0gc3VtKHNoaXBwaW5nLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB0b3RhbF9wb3B1bGF0aW9uID0gc3VtKHRvdGFsX3BvcHVsYXRpb24sIG5hLnJtID0gVFJVRSkpCgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKUGxvdCB0aGUgb3ZlcmFsbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIGFuZCBXYXJkCgpgYGB7cn0KCmRpdmlzaW9uX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uLCBmaWxsPWRpdmlzaW9uKSwgYWxwaGE9MC44KSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24pKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lID0gIiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgpgYGB7cn0KCndhcmRfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuOCkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIG5jb2w9NikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWU9IkRpdmlzaW9uIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICJEaXZpc2lvbiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDaXR5OiB0b3RhbCBwb3B1bGF0aW9uIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MyLnBuZyIpLCBoZWlnaHQ9MTAsIHdpZHRoPTEyKQoKYGBgCgpBcHByb3hpbWF0ZWx5LCBob3cgbWFueSBwZXJzb24teWVhcnMgb2YgZm9sbG93LXVwIGRvIHdlIGhhdmU/CgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyh5ZWFyLCBsZW5ndGgsIC5uYW1lcyA9ICJ5ZWFycyIpLAogICAgICAgICAgICBhY3Jvc3MoYyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB0b3RhbF9wb3B1bGF0aW9uKSwgc3VtKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5kb3VibGUpLCBjb21tYSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpDaGFuZ2UgaW4gcG9wdWxhdGlvbiBieSB3YXJkCgpgYGB7cn0KCndhcmRfcG9wcyAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3AgPSAobGFzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSAtIGZpcnN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKS9maXJzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSkgJT4lCiAgbXV0YXRlKHBjdF9jaGFuZ2VfcG9wID0gcGVyY2VudChwY3RfY2hhbmdlX3BvcCkpICU+JQogIGFycmFuZ2UocGN0X2NoYW5nZV9wb3ApICU+JQogIGRhdGF0YWJsZSgpCiAgCgoKYGBgCgoKIyMjIyAzLjMgUG9wdWxhdGlvbiBieSBhZ2UgYW5kIHNleAoKYGBge3J9CgphZ2Vfc2V4IDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImFnZV9zZXhfcG9wdWxhdGlvbiIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhtYWxlLCBmZW1hbGUpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJzZXgiKQoKI2NvbGxhcHNlIGRvd24gdG8gc21hbGxlciBhZ2UgZ3JvdXBzIHRvIGJlIG1hbmFnZWFibGUKYWdlX3NleCA8LSBhZ2Vfc2V4ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZSA9PSAiMCB0byA0IiB+ICIwMCB0byAwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjUgdG8gOSIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxMCB0byAxNCIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxNSB0byAxOSIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyMCB0byAyNCIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyNSB0byAyOSIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzMCB0byAzNCIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzNSB0byAzOSIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0MCB0byA0NCIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0NSB0byA0OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1MCB0byA1NCIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1NSB0byA1OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICI2MCAmIHVwIikpICU+JQogIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUKICB1bmdyb3VwKCkKCgoKbV9hZ2Vfc2V4IDwtIGxtKHZhbHVlIH4gc3BsaW5lczo6bnMoeWVhciwga25vdHMgPSAzKSphZ2Uqc2V4LCBkYXRhID0gYWdlX3NleCkKCnN1bW1hcnkobV9hZ2Vfc2V4KQoKYWdlX2xldmVscyA8LSBhZ2Vfc2V4ICU+JSBzZWxlY3QoYWdlKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbCgpIAoKYWdlX3NleF9uZCA8LSAKICBjcm9zc2luZygKICAgIGFnZT1hZ2VfbGV2ZWxzLAogICAgc2V4PWMoIm1hbGUiLCAiZmVtYWxlIiksCiAgICB5ZWFyID0gMTk1MDoxOTYzCiAgKQoKcHJlZF9wb3BzIDwtIGFnZV9zZXhfbmQgJT4lIG1vZGVscjo6YWRkX3ByZWRpY3Rpb25zKG1fYWdlX3NleCkKCnByZWRfcG9wcyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wcmVkLCBjb2xvdXI9YWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoc2V4fi4pICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwgMTI1MDAwKSkKCiNIb3cgd2VsbCBkbyB0aGV5IG1hdGNoIHVwIHdpdGggb3VyIG92ZXJhbGwgcG9wdWxhdGlvbnM/CnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2Uoc3VtX3ByZWRfcG9wID0gc3VtKHByZWQpKSAlPiUKICByaWdodF9qb2luKG92ZXJhbGxfcG9wcykgJT4lCiAgc2VsZWN0KHllYXIsIHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvdXI9bmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSwgbGltaXRzID0gYyg4MDAwMDAsIDEyNTAwMDApKQoKcHJlZF9wb3BzICU+JQogIGdyb3VwX2J5KHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShwcmVkKSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHNleF9yYXRpbyA9IGZpcnN0KHN1bSkvbGFzdChzdW0pKQpgYGAKClBvcHVsYXRpb24gcHlyYW1pZHMKCmBgYHtyfQoKbGFiZWxfYWJzIDwtIGZ1bmN0aW9uKHgpIHsKICBjb21tYShhYnMoeCkpCn0KCgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZSh5ZWFyX3BvcCA9IHN1bShwcmVkKSwKICAgICAgICAgYWdlX3NleF9wY3QgPSBwZXJjZW50KHByZWQveWVhcl9wb3AsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0ibWFsZSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJmZW1hbGUiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGFnZSwgZmlsbCA9IHNleCwgCiAgICAgICAgeSA9IGlmZWxzZSh0ZXN0ID0gc2V4ID09ICJGZW1hbGUiLHllcyA9IC1wcmVkLCBubyA9IHByZWQpKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBhZ2Vfc2V4X3BjdCksCiAgICAgICAgICAgIHBvc2l0aW9uPSBwb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBjb2xvdXI9IndoaXRlIiwgc2l6ZT0yLjUpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfYWJzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibWVkaXVtc2VhZ3JlZW4iLCAicHVycGxlIiksIG5hbWU9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0ID0gMSwgdmp1c3Q9MC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSIiLCB5PSIiKSAKCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMy5wbmciKSwgd2lkdGg9MTApCgoKYGBgCgpOb3QgcGVyZmVjdCwgYnV0IHJlc29uYWJseSBnb29kLiBCdXQgYWhoaGhoLi4uIHRoZSBhZ2UgZ3JvdXBzIGRvbid0IGFsaWduIHdpdGggdGhlIGNhc2Ugbm90aWZpY2F0aW9uIGFnZSBncm91cHMhIENvbWUgYmFjayB0byB0aGluayBhYm91dCB0aGlzIGxhdGVyLgoKCiMjIyA0LiBUdWJlcmN1bG9zaXMgY2FzZXMKCkltcG9ydCB0aGUgdHViZXJjdWxvc2lzIGNhc2VzIGRhdGFzZXQKCgojIyMjIDQuMSBPdmVyYWxsIG5vdGlmaWNhdGlvbnMKCk92ZXJhbGwsIGJ5IHllYXIuCgpgYGB7cn0KCmNhc2VzX2J5X3llYXIgPC0gcmVhZF94bHN4KCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJieV95ZWFyIikKCmNhc2VzX2J5X3llYXIlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfeWVhciA8LSBjYXNlc19ieV95ZWFyICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpQbG90IHRoZSBvdmVyYWxsIG51bWJlciBvZiBjYXNlIG5vdGlmaWVkIHBlciB5ZWFyLCBieSBwdWxtb25hcnkgYW5kIGV4dHJhIHB1bG1vbmFyeSBjbGFzc2lmaWNhdGlvbi4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciAlPiUKICBzZWxlY3QoLXRvdGFsX25vdGlmaWNhdGlvbnMsIC15ZWFyKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMocHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMsIGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAicHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAibm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT12YWx1ZSwgeD15ZWFyMiwgZ3JvdXAgPSBuYW1lLCBmaWxsPW5hbWUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgCgpgYGAKCiMjIyMgNC4yIE5vdGlmaWNhdGlvbnMgYnkgRGl2aXNpb24KClJlYWQgaW4gdGhlIGRhdGFzZXRzIGFuZCBtZXJnZSB0b2dldGhlci4KCmBgYHtyfQoKI2xpc3QgYWxsIHRoZSBzaGVldHMKYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIpCgojZ2V0IHRoZSB3YXJkIHNoZWV0cwp3YXJkX3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiYnlfd2FyZCIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpjYXNlc19ieV93YXJkX3NleF95ZWFyIDwtIG1hcF9kZih3YXJkX3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpBZ2dyZWdhdGUgdG9nZXRoZXIgdG8gZ2V0IGNhc2VzIGJ5IGRpdmlzaW9uCgpgYGB7cn0KCmNhc2VzX2J5X2RpdmlzaW9uIDwtIGNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbGVmdF9qb2luKHdhcmRfbG9va3VwKSAlPiUKICBncm91cF9ieShkaXZpc2lvbiwgeWVhciwgdGJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKGNhc2VzLCBuYS5ybSA9IFRSVUUpKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfZGl2aXNpb24gJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfZGl2aXNpb24gICU+JQogIHNlbGVjdCgteWVhcjIpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKYGBgCgojIyMjIDQuMyBOb3RpZmljYXRpb25zIGJ5IHdhcmQKCmBgYHtyfQoKCmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBncm91cF9ieSh3YXJkLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV93YXJkIDwtIGNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjgpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgojIyMjIDQuNCBOb3RpZmljYXRpb25zIGJ5IGFnZSBhbmQgc2V4CgpBcyB3ZSBkb24ndCBoYXZlIGRlbm9taW5hdG9ycywgd2Ugd2lsbCBqdXN0IG1vZGVsIHRoZSBjaGFuZ2UgaW4gY291bnRzLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCmFnZV9zZXhfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV9hZ2Vfc2V4IiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X2FnZV9zZXggPC0gbWFwX2RmKGFnZV9zZXhfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfYWdlX3NleCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKCgojIyMgNSBUQiBpbmNpZGVuY2UKCiMjIyMgNS4xIE92ZXJhbGwgVEIgaW5jaWRlbmNlCgpOb3cgY2FsY3VsYXRlIGluY2lkZW5jZSBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uCgpNZXJnZSB0aGUgbm90aWZpY2F0aW9uIGFuZCBwb3B1bGF0aW9uIGRlbm9taW5hdG9yIGRhdGFzZXRzIHRvZ2V0aGVyLgoKSGVyZSB3ZSBuZWVkIHRvIGluY2x1ZGUgdGhlIHdob2xlIHBvcHVsYXRpb24gKHdpdGggc2hpcHBpbmcgYW5kIGluc3RpdHV0aW9ucykgYXMgdGhleSBhcmUgaW5jbHVkZWQgaW4gdGhlIG5vdGlmaWNhdGlvbnMuCgpgYGB7cn0KCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfcG9wcyAlPiUKICBsZWZ0X2pvaW4oY2FzZXNfYnlfeWVhcikKCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfaW5jICU+JQogIG11dGF0ZShpbmNfcHVsbV8xMDBrID0gcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY19lcF8xMDBrID0gYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2AvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY18xMDBrID0gdG90YWxfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkKCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyLCBpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGssIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKYGBge3J9CgpvdmVyYWxsX2luYyAlPiUKICBzZWxlY3QoeWVhcjIsIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoaW5jX3B1bG1fMTAwaywgYGluY19lcF8xMDBrYCkpICU+JQogIG11dGF0ZShuYW1lID0gY2FzZV93aGVuKG5hbWUgPT0gImluY19wdWxtXzEwMGsiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAiaW5jX2VwXzEwMGsiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBpbmNpZGVuY2UgYnkgRGl2aXNpb24KCmBgYHtyfQoKZGl2aXNpb25faW5jIDwtIGRpdmlzaW9uX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X2RpdmlzaW9uKQoKCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gY2FzZXMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApCgpkaXZpc2lvbl9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGRpdmlzaW9uLCB0Yl90eXBlLCBpbmNfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmRpdmlzaW9uX2luYyAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9aW5jXzEwMGssIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlLCBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCiMjIyMgNS4yIFRCIGluY2lkZW5jZSBieSBXYXJkCgpIZXJlIHdlIHdpbGwgZmlsdGVyIG91dCB0aGUgaW5zdGl0dXRpb25zIGFuZCBoYXJib3VyIGZyb20gdGhlIGRlbm9taW5hdG9ycywgYXMgd2UgZG9uJ3QgaGF2ZSByZWxpYWJsZSBwb3B1bGF0aW9uIGRlbm9taW5hdG9ycyBmb3IgdGhlbS4KCmBgYHtyfQoKd2FyZF9pbmMgPC0gd2FyZF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV93YXJkKQoKCndhcmRfaW5jIDwtIHdhcmRfaW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKQoKd2FyZF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIHdhcmQsIHRiX3R5cGUsIGluY18xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgpgYGB7cn0KCndhcmRfaW5jICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1pbmNfMTAwaywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiSW5jaWRlbmNlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKCmBgYAoKT24gYSBtYXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQoKc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCgoKYGBgCgoKIyMjIDYuIFRCIE1vcnRhbGl0eQoKIyMjIyA2LjEgT3ZlcmFsbCBNb3J0YWxpdHkKCkltcG9ydCB0aGUgVEIgbW9ydGFsaXR5IGRhdGEuCgpGaXJzdCwgb3ZlcmFsbCBkZWF0aHMuIE5vdGUgdGhhdCBpbiB0aGUgb3JpZ2luYWwgcmVwb3J0cywgd2UgaGF2ZSBhIHB1bG1vbmFyeSBUQiBkZWF0aCByYXRlIHBlciBtaWxsaW9uIGZvciBhbGwgeWVhcnMsIGFuZCBudW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMgZm9yIGVhY2ggeWVhciBhcGFydCBmcm9tIDE5NTAuCgpgYGB7cn0KCiNnZXQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHNoZWV0cwpkZWF0aHNfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJkZWF0aHMiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKb3ZlcmFsbF9kZWF0aHMgPC0gbWFwX2RmKGRlYXRoc19zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpvdmVyYWxsX2RlYXRocyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKUGxvdCB0aGUgcmF3IG51bWJlcnMgb2YgcHVsbW9uYXJ5IGRlYXRocwoKYGBge3J9CgpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhzKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBsYWJzKHk9IlB1bG1vbmFyeSBUQiBkZWF0aHMgcGVyIHllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHRpdGxlID0gIk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHbGFzZ293LCAxOTUwLTE5NjMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogbm8gZGF0YSBmb3IgMTk1MCIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCk5vdyB0aGUgaW5jaWRlbmNlIG9mIHB1bG1vbmFyeSBUQiBkZWF0aAoKYGBge3J9Cm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoeT0iQW5udWFsIGluY2lkZW5jZSBvZiBkZWF0aCAocGVyIDEwMCwwMDApIiwKICAgICAgIHggPSAiWWVhciIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIDYuIFRhYmxlIDEKCk1ha2UgVGFibGUgMSBoZXJlLCBhbmQgc2F2ZSBmb3IgcHVibGljYXRpb24uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2luYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBpbmNfcHVsbV8xMDBrLAogICAgICAgICAgICAgICAgICAgICBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCwgaW5jX2VwXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIHRvdGFsX25vdGlmaWNhdGlvbnMsIGluY18xMDBrKSkgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfZGVhdGhzICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfZGVhdGhzLCBwdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfnJvdW5kKC4sIGRpZ2l0cz0xKSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgCgpgYGAKCgoKCiMjIyA3LiBPdmVyYWxsIHB1bG1vbmFyeSBUQiBtb2RlbAoKCiMjIyMgNy4xIEZJdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKRmlyc3QgbW9kZWwgd2lsbCBpbnZlc3RpZ2F0ZSB0aGUgaW1wYWN0IG9mIG1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIG9uIHB1bG1vbmFyeSBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIHVzaW5nIGFuIGludGVycnVwdGVkIHRpbWUgc2VyaWVzIGFuYWx5c2lzLgoKU2V0IHVwIHRoZSBkYXRhCgpgYGB7cn0KCm1kYXRhMSA8LSBvdmVyYWxsX2luYyAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBtdXRhdGUoeV9udW0gPSAxOm5yb3coLikpICU+JQogIHJlbmFtZShleHRyYXB1bG1vbmFyeV9ub3RpZmljYXRpb25zID0gYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApCgpgYGAKCgpXb3JrIG9uIHRoZSBwcmlvcnMgYSBiaXQKCkJhc2ljIHByaW9yCgpgYGB7cn0KCmJhc2ljX3ByaW9yIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMjUpLCBjbGFzcyA9IGIpKQpgYGAKCkxvb2sgYXQgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIGNvdW50cyAoY291bnRzIG9mIHB1bG1vbmFyeSBub3RpZmljYXRpb25zIGFyZSB3aGF0IHdlIGFyZSBwcmVkaWN0aW5nKQoKYGBge3J9CgojTWVhbiBvZiBjb3VudHMgcGVyIHllYXIKbWVhbihtZGF0YTEkcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhMSRwdWxtb25hcnlfbm90aWZpY2F0aW9ucykKCmBgYAoKClF1aXRlIGEgYml0IG9mIG92ZXItZGlzcGVyc2lvbiBoZXJlLCBzbyBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24gbWlnaHQgYmUgYSBiZXR0ZXIgY2hvaWNlIG9mIGRpc3RyaWJ1dGlvbmFsIGZhbWlseSB0aGFuIFBvaXNzb24uCgpTbGlnaHRseSBtb3JlIGluZm9ybWF0aXZlIHByaW9yICgid2Vha2x5IGluZm9ybWF0aXZlIiByZWFsbHkpCgpgYGB7cn0KCmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDUwMCwgdG8gPSA1MDAwLCBieSA9IDEwKSksCiAgICAgICBhZXMoeCA9IHgsIHkgPSBkZ2FtbWEoeCwgc2hhcGUgPSAyLCByYXRlID0gMC4wMDEpKSkgKwogIGdlb21fYXJlYShjb2xvciA9ICJ0cmFuc3BhcmVudCIsIAogICAgICAgICAgICBmaWxsID0gIiNERTBEOTIiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKE5VTEwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoNTAwLCA1MDAwKSkgKwogIGdndGl0bGUoZXhwcmVzc2lvbihicm1zfn5nYW1tYSgyKiIsICIqMC4wMDEpfnNoYXBlfnByaW9yKSkKCgpgYGAKCkZpdCBhIG1vZGVsIHdpdGggb25seSBwcmlvcnMKCmBgYHtyfQoKd2luZm9ybV9wcmlvciA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgyLCAwLjAwMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4yNSksIGNsYXNzID0gYikpCgoKbV9wdWxtb25hcnlfcHJpb3IgPC0gYnJtKAogIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICBvZmZzZXQobG9nKHRvdGFsX3BvcHVsYXRpb24pKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvciwKICAgICAgICAgICAgICAgICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogICAgICAgICAgICAgICAgICBiYWNrZW5kPSJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfcHJpb3IpCmNvbmRpdGlvbmFsX2VmZmVjdHMobV9wdWxtb25hcnlfcHJpb3IpCgpgYGAKCk5vdyBmaXQgdGhlIG1vZGVsIHdpdGggdGhlIHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMKCgpgYGB7cn0KbV9wdWxtb25hcnlfb3ZlcmFsbCA8LSBicm0oCiAgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgIG9mZnNldChsb2codG90YWxfcG9wdWxhdGlvbikpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGExLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKc3VtbWFyeShtX3B1bG1vbmFyeV9vdmVyYWxsKQpwbG90KG1fcHVsbW9uYXJ5X292ZXJhbGwpCnBwX2NoZWNrKG1fcHVsbW9uYXJ5X292ZXJhbGwsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCgoKCiMjIyMgNy4yIFN1bW1hcmlzZSBjaGFuZ2UgaW4gQ05ScwoKU3VtbWFyaXNlIHRoZSBwb3N0ZXJpb3IKCmBgYHtyfQoKZjFiIDwtIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMSwgbW9kZWwgPSBtX3B1bG1vbmFyeV9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbiwgb3V0Y29tZSA9IGluY19wdWxtXzEwMGssIGdyb3VwaW5nX3Zhcj1OVUxMKQogIApmMWIKYGBgCgpNYWtlIHRoaXMgaW50byBhIGZpZ3VyZQoKYGBge3J9CgpmMWEgPC0gc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgI2xlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuNSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIpKQoKKGYxYSAvIGYxYikgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YxLnBuZyIpKQoKYGBgCgoKU3VtbWFyeSBvZiBjaGFuZ2UgaW4gbm90aWZpY2F0aW9ucwoKYGBge3J9CgpzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9bWRhdGExLCBtb2RlbD1tX3B1bG1vbmFyeV9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXRvdGFsX3BvcHVsYXRpb24sIGdyb3VwaW5nX3Zhcj1OVUxMKSAlPiUKICBtYXAoZGF0YXRhYmxlKQoKYGBgCihBbHRlcm5hdGl2ZSB3YXkgLSBrZWVwIGluIGZvciBub3cpCgpgYGB7cn0KCm92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzIDwtIG1kYXRhMSAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCB0b3RhbF9wb3B1bGF0aW9uLCBwdWxtb25hcnlfbm90aWZpY2F0aW9ucykgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1NykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9pbW1lZGlhdGUgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiAgdW5ncm91cCgpCgpvdmVyYWxsX3Bvc3RfZHJhd3MgPC0gbWRhdGExICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHRvdGFsX3BvcHVsYXRpb24sIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NiwxOTU4KSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X292ZXJhbGwpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkgJT4lCiAgZ3JvdXBfYnkoLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Bvc3QgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiAgdW5ncm91cCgpCgoKb3ZlcmFsbF9zbG9wZV9kcmF3cyA8LSBtZGF0YTEgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgdG90YWxfcG9wdWxhdGlvbiwgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTUwLCAxOTU2LCAxOTU4LCAxOTYzKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X292ZXJhbGwpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3llYXJzID0gbGVuZ3RoKHllYXIpLCAuYnk9YWNmX3BlcmlvZCkgJT4lCiAgZ3JvdXBfYnkoYWNmX3BlcmlvZCwgLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Nsb3BlID0gKChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKS9uX3llYXJzKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjKGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcGN0X2NoYW5nZV9zbG9wZSkgJT4lCiAgbXV0YXRlKHJhdGlvX2FubnVhbF9zbG9wZSA9IGBjLiBwb3N0LWFjZmAgLyBgYS4gcHJlLWFjZmApCgoKYGBgCgpDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBlZmZlY3QgYW5kIHBvc3QgZWZmZWN0IG9mIEFDRgoKYGBge3J9CgpsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfcG9zdF9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXBjdF9jaGFuZ2VfcG9zdCkpICsKICBnZW9tX2hkcigKICAgIGFlcyhmaWxsID0gYWZ0ZXJfc3RhdChwcm9icykpLCAKICAgIGFscGhhID0gMSkgKwogICNnZW9tX2hkcl9wb2ludHMoYWVzKGNvbG91ciA9IGFmdGVyX3N0YXQocHJvYnMpKSwgc2l6ZT0wLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAuMjUsIGxhYmVsLnkgPSAtMC4yNSwgc2l6ZT00KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA1KSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0iRSIsIG5hbWU9IiIpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgICAgIHk9IlBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdDogZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iQm91bmRhcmllcyBhcmUgcG9zdGVyaW9yIGRlc25pdHkgaW50ZXJ2YWxzIGZyb20gNDAwMCBkcmF3cyIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgY2hhbmdlIGluIHNsb3BlCgpgYGB7cn0KCmxlZnRfam9pbihvdmVyYWxsX2ltbWVkaWF0ZV9kcmF3cywgb3ZlcmFsbF9zbG9wZV9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSkpICsKICBnZW9tX2hkcigKICAgIGFlcyhmaWxsID0gYWZ0ZXJfc3RhdChwcm9icykpLCAKICAgIGFscGhhID0gMSkgKwogICNnZW9tX2hkcl9wb2ludHMoYWVzKGNvbG91ciA9IGFmdGVyX3N0YXQocHJvYnMpKSwgc2l6ZT0wLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICAjc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLjI1LCBsYWJlbC55ID0gMC4wMiwgc2l6ZT00KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA1KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxMCkpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb249IkUiLCBuYW1lPSIiKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAogICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIsCiAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIGRyYXdzIGZyb20gcG9zdGVpb3IgZGlzdHJpYnV0aW9uIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCmBgYAoKCgoKIyMjIyA3LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYgPC0gY2FsY3VhdGVfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMSwgbW9kZWw9bV9wdWxtb25hcnlfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHRvdGFsX3BvcHVsYXRpb24pCgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKClRvdGFsIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKCiMjIyA4LiBFeHRyYS1wdWxtb25hcnkgVEIgbm90aWZpY2F0aW9ucwoKIyMjIyA4LjEgRml0IHRoZSBtb2RlbAoKYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GQUxTRX0KCm1fZXh0cmFwX292ZXJhbGwgPC0gYnJtKAogIGV4dHJhcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgb2Zmc2V0KGxvZyh0b3RhbF9wb3B1bGF0aW9uKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTEsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24oKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gYmFzaWNfcHJpb3IsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpzdW1tYXJ5KG1fZXh0cmFwX292ZXJhbGwpCnBsb3QobV9leHRyYXBfb3ZlcmFsbCkKcHBfY2hlY2sobV9leHRyYXBfb3ZlcmFsbCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCmBgYAoKCmBgYHtyfQpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fZXh0cmFwX292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uLCBvdXRjb21lPWluY19lcF8xMDBrKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSwgd2lkdGg9MTApCgpgYGAKCgojIyMjIDguMiBTdW1tYXJ5IG9mIGNoYW5nZQoKQS4gUGVyY2VudGFnZSBjaGFuZ2UgaW4gbW9ydGFsaXR5LCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhMSwgbW9kZWwgPSBtX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAoKCgojIyMjIDguMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fZXh0cmFwX292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uKQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKVG90YWwgZXh0cmEgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgYmV0d2VlbiAxOTU4IGFuZCAxOTYzCgpgYGB7cn0KCm92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCiMjIyA5LiBXYXJkIGxldmVsIG1vZGVsCgojIyMjIDkuMSBGaXQgdGhlIG1vZGVsCgpgYGB7cn0KCm1kYXRhMiA8LSB3YXJkX2luYyAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIGdyb3VwX2J5KHdhcmQpICU+JQogIG11dGF0ZSh5X251bSA9IHJvd19udW1iZXIoKSkgJT4lCiAgdW5ncm91cCgpCgoKCmBgYAoKKE5vdGUgdGhlIGRlbm9taW5hdG9yIHdpdGhvdXQgaW5zdGl0dXRpb25hbGlzZWQgcGVvcGxlIGFuZCAic2hpcHBpbmciISkKCmBgYHtyfQojd2Vha2x5IGluZm9ybWF0aXZlIHByaW9ycyBmb3IgbXVsdGlsZXZlbCBtb2RlbApiYXNpY19wcmlvcjIgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4xKSwgY2xhc3MgPSBiKSwKICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIikpCgoKZ2dwbG90KGRhdGEgPSB0aWJibGUoeCA9IHNlcShmcm9tID0gMCwgdG8gPSA1MDAsIGJ5ID0gMTApKSwKICAgICAgIGFlcyh4ID0geCwgeSA9IGRnYW1tYSh4LCBzaGFwZSA9IDEsIHJhdGUgPSAwLjAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgc2NhbGVfeV9jb250aW51b3VzKE5VTEwsIGJyZWFrcyA9IE5VTEwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgNTAwKSkgKwogIGdndGl0bGUoZXhwcmVzc2lvbihicm1zfn5nYW1tYSgxKiIsICIqMC4wMSl+c2hhcGV+cHJpb3IpKQoKd2luZm9ybV9wcmlvcjIgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGNhdWNoeSgwLDUpLCBjbGFzcz0ic2QiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz0iY29yIikpCmBgYAoKCmBgYHtyfQoKbV9wdWxtb25hcnlfd2FyZF9wcmlvciA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgKyB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtIHwgd2FyZCkgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMiwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvcjIsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCmNvbmRpdGlvbmFsX2VmZmVjdHMobV9wdWxtb25hcnlfd2FyZF9wcmlvcikKCgpgYGAKCk5vdyBmaXQgdGhlIG1vZGVsIHdpdGggZGF0YQoKYGBge3J9Cm1fcHVsbW9uYXJ5X3dhcmQgPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICgxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTIsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IyLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIikKCnN1bW1hcnkobV9wdWxtb25hcnlfd2FyZCkKcGxvdChtX3B1bG1vbmFyeV93YXJkKQpwcF9jaGVjayhtX3B1bG1vbmFyeV93YXJkLCB0eXBlPSdlY2RmX292ZXJsYXknKQoKCmBgYAoKCmBgYHtyfQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEyLCBtb2RlbD1tX3B1bG1vbmFyeV93YXJkLCBvdXRjb21lID0gaW5jXzEwMGssIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXIgPSB3YXJkLCB3YXJkKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNC5wbmciKSwgd2lkdGg9MTAsIGhlaWdodD0xMikKCmBgYAoKIyMjIyA5LjIgU3VtbWFyeSBvZiBjaGFuZ2UKCkEuIHBlcmNlbnRhZ2UgaW5jcmVhc2UgaW4gQ05SLCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKd2FyZF9jaGFuZ2UgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhID0gbWRhdGEyLCBtb2RlbCA9IG1fcHVsbW9uYXJ5X3dhcmQsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9d2FyZCkgCgp3YXJkX2NoYW5nZSAlPiUKICBtYXAoZGF0YXRhYmxlKQoKYGBgCgpBcyBhIHN1cHBsZW1lbnRhcnkgZmlndXJlCgpgYGB7cn0KICAKd2FyZF9jaGFuZ2UkaW1tZWRpYXRlX2NoYW5nZSAlPiUKICBhcnJhbmdlKGFjZl9pbmMxMDBrX3JyKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9pbmMxMDBrX3JyLCB5bWluPWFjZl9pbmMxMDBrX3JyLmxvd2VyLCB5bWF4PWFjZl9pbmMxMDBrX3JyLnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZCwgYWNmX2luYzEwMGtfcnIpLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX2luYzEwMGtfcnIpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYihvcHRpb24gPSAiRCIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjgsMy4wKSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIHBvc3RlcmlvciBwcmVkaWN0ZWQgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDA7IDk1JSBVSSlcbkFDRiAoMTk1NykgdnMuIEJlZm9yZSBBQ0YgKDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczUucG5nIikpCgpgYGAKCgpgYGB7cn0KCndhcmRfY2hhbmdlJHBvc3RfY2hhbmdlICU+JQogIGFycmFuZ2UoYWNmX2luYzEwMGtfcnIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX2luYzEwMGtfcnIsIHltaW49YWNmX2luYzEwMGtfcnIubG93ZXIsIHltYXg9YWNmX2luYzEwMGtfcnIudXBwZXIsIAogICAgICAgICAgICAgICAgICAgICAgeD1mY3RfcmVvcmRlcih3YXJkLCBhY2ZfaW5jMTAwa19yciksCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhY2ZfaW5jMTAwa19ycikpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19iKG9wdGlvbiA9ICJEIikgKwogICNzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjgsMy4wKSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIHBvc3RlcmlvciBwcmVkaWN0ZWQgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDA7IDk1JSBVSSlcbkFmdGVyIEFDRiAoMTk1OCkgdnMuIEJlZm9yZSBBQ0YgKDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M2LnBuZyIpKQoKCmBgYAoKCnBlcmNlbnRhZ2UgY2hhbmdlID0gKGZpbmFsIHZhbHVlIC0gaW5pdGlhbCB2YWx1ZSkgLyBpbml0aWFsIHZhbHVlCgpgYGB7cn0KCndhcmRfY2hhbmdlJHNsb3BlX2NoYW5nZSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PXBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCAsIHltaW49cGN0X2NoYW5nZV9sb3dlcl9vdmVyYWxsICwgeW1heD1wY3RfY2hhbmdlX3VwcGVyX292ZXJhbGwgLAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXA9YWNmX3BlcmlvZCwgY29sb3VyPWFjZl9wZXJpb2QsCiAgICAgICAgICAgICAgICAgICAgICB4ID0gZmN0X3Jlb3JkZXIod2FyZCwgcGN0X2NoYW5nZV9lcHJlZF9vdmVyYWxsICkpKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID1wZXJjZW50KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgIiM0RDZDRkEiKSkgKwogICNzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjgsMy4wKSkgKwogIGxhYnModGl0bGU9IkludGVydmVudGlvbiBlZmZlY3Qgb2YgbWFzcyBtaW5pYXR1cmUgY2hlc3QgWC1yYXkgaW4gR2xhc2dvdyIsCiAgICAgICBzdWJ0aXRsZT0iQnkgbXVuaWNpcGFsIHdhcmQiLAogICAgICAgeD0iIiwKICAgICAgIHk9Ik1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDk1JSBDckkpXG4gQmVmb3JlIEFDRiAoMTk1MC0xOTU2KSB2cy4gYWZ0ZXIgQUNGICgxOTU4LTE5NjMpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKYGBgCgooQWx0ZXJuYXRpdmUgZmlndXJlIC0ga2VlcCBpbiBmb3IgdGhlIG1pbnV0ZSkKCklzIHRoZXJlIGFueSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBpbmNyZWFzZSBhbmQgYSkgcG9zdC1pbnRlcnZlbnRpb24gKDE5NTgpIGVmZmVjdCwgYW5kIGIpIHBvc3QgaW50ZXJ2ZW50aW9uIHNsb3BlICgxOTU4LTE5NjMpCgpgYGB7cn0KCiMgd2FyZF9jb3JzIDwtIHdhcmRfaW1wYWN0X291dCAlPiUKIyAgIHNlbGVjdCh3YXJkLCBpbW1lZGlhdGVfZWZmZWN0ID0gYWNmX2luYzEwMGtfcnIsCiMgICAgICAgICAgICAgICAgaW1tZWRpYXRlX2VmZmVjdF9sb3dlciA9IGFjZl9pbmMxMDBrX3JyLmxvd2VyLAojICAgICAgICAgICAgICAgIGltbWVkaWF0ZV9lZmZlY3RfdXBwZXIgPSBhY2ZfaW5jMTAwa19yci51cHBlcikgJT4lCiMgICByaWdodF9qb2luKAojICAgICB3YXJkX3B1bG1faW1wYWN0MiAlPiUgCiMgICAgICAgc2VsZWN0KHdhcmQsIHBvc3RfZWZmZWN0ID0gYWNmX2luYzEwMGtfcnIsCiMgICAgICAgICAgICAgICAgcG9zdF9lZmZlY3RfbG93ZXIgPSBhY2ZfaW5jMTAwa19yci5sb3dlciwKIyAgICAgICAgICAgICAgICBwb3N0X2VmZmVjdF91cHBlciA9IGFjZl9pbmMxMDBrX3JyLnVwcGVyKQojICAgKSAlPiUKIyAgIHJpZ2h0X2pvaW4oCiMgICAgIHdhcmRfcHVsbV9pbXBhY3QzICU+JQojICAgICAgIGZpbHRlcihhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiKSAlPiUKIyAgICAgICBzZWxlY3Qod2FyZCwgc2xvcGVfZWZmZWN0ID0gcGN0X2NoYW5nZV9lcHJlZF9hbm51YWwsCiMgICAgICAgICAgICAgIHNsb3BlX2VmZmVjdF9sb3dlciA9IHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsLAojICAgICAgICAgICAgICBzbG9wZV9lZmZlY3RfdXBwZXIgPSBwY3RfY2hhbmdlX3VwcGVyX2FubnVhbCkKIyAgICkKIyAKIyB3YXJkX2NvcnMgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9aW1tZWRpYXRlX2VmZmVjdCwgeG1pbj1pbW1lZGlhdGVfZWZmZWN0X2xvd2VyLCB4bWF4PWltbWVkaWF0ZV9lZmZlY3RfdXBwZXIsCiMgICAgICAgICAgICAgIHk9cG9zdF9lZmZlY3QsIHltaW49cG9zdF9lZmZlY3RfbG93ZXIsIHltYXg9cG9zdF9lZmZlY3RfdXBwZXIsCiMgICAgICAgICAgICAgIGdyb3VwID0gd2FyZCkpICsKIyAgIGdlb21fZXJyb3JiYXIoKSArCiMgICBnZW9tX2Vycm9yYmFyaCgpICsKIyAgIGdlb21fcG9pbnQoKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiMgICB0aGVtZV9nZ2Rpc3QoKSArCiMgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKIyAgICAgICAgeT0iUmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoMTk1OCB2cy4gMTk1NilcblBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdCIsCiMgICAgICAgIHg9IlJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDE5NTcgdnMuIDE5NTYpXG5JbW1lZGlhdGUgaW1wYWN0IiwKIyAgICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBtdW5pY2lwYWwgd2FyZHMiKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiMgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQojIAojIHdhcmRfY29ycyAlPiUKIyAgIGdncGxvdChhZXMoeD1pbW1lZGlhdGVfZWZmZWN0LCB4bWluPWltbWVkaWF0ZV9lZmZlY3RfbG93ZXIsIHhtYXg9aW1tZWRpYXRlX2VmZmVjdF91cHBlciwKIyAgICAgICAgICAgICAgeT1zbG9wZV9lZmZlY3QsIHltaW49c2xvcGVfZWZmZWN0X2xvd2VyLCB5bWF4PXNsb3BlX2VmZmVjdF91cHBlciwKIyAgICAgICAgICAgICAgZ3JvdXAgPSB3YXJkKSkgKwojICAgZ2VvbV9lcnJvcmJhcigpICsKIyAgIGdlb21fZXJyb3JiYXJoKCkgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwojICAgdGhlbWVfZ2dkaXN0KCkgKwojICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgbWVhbiByYXRlIG9mIGNoYW5nZSIsCiMgICAgICAgIHk9IlBvc3QgQUNGIG1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIiwKIyAgICAgICAgeD0iUmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoMTk1NyB2cy4gMTk1NilcbkltbWVkaWF0ZSBpbXBhY3QiLAojICAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIG11bmljaXBhbCB3YXJkcyIpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKIyAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKCmBgYAoKVHJ5IGEgZGlmZmVyZW50IHdheSB3aXRoIHRoZSBmdWxsIGRpc3RyaWJ1dGlvbiBvZiBwb3N0ZXJpb3JzCgoKYGBge3J9CgojIHdhcmRfaW1tZWRpYXRlX2RyYXdzIDwtIG1kYXRhMiAlPiUKIyAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGNhc2VzLCB3YXJkKSAlPiUKIyAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTcpKSAlPiUKIyAgIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKIyAgIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiMgICBncm91cF9ieSh3YXJkLCAuZHJhdykgJT4lCiMgICBzdW1tYXJpc2UocGN0X2NoYW5nZV9pbW1lZGlhdGUgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiMgICBhcnJhbmdlKHdhcmQpICU+JQojICAgdW5ncm91cCgpCiMgCiMgd2FyZF9wb3N0X2RyYXdzIDwtIG1kYXRhMiAlPiUKIyAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGNhc2VzLCB3YXJkKSAlPiUKIyAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTgpKSAlPiUKIyAgIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKIyAgIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiMgICBncm91cF9ieSh3YXJkLCAuZHJhdykgJT4lCiMgICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3N0ID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQojICAgYXJyYW5nZSh3YXJkKSAlPiUKIyAgIHVuZ3JvdXAoKQojIAojIAojIHdhcmRfc2xvcGVfZHJhd3MgPC0gbWRhdGEyICU+JQojICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgY2FzZXMsIHdhcmQpICU+JQojICAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTAsIDE5NTYsIDE5NTgsIDE5NjMpKSAlPiUKIyAgIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKIyAgIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiMgICB1bmdyb3VwKCkgJT4lCiMgICBtdXRhdGUobl95ZWFycyA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiA3LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+IDYpKSAlPiUKIyAgIGdyb3VwX2J5KHdhcmQsIGFjZl9wZXJpb2QsIC5kcmF3KSAlPiUKIyAgIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Nsb3BlID0gKChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKS9uX3llYXJzKSAlPiUKIyAgIGRpc3RpbmN0KCkgJT4lCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYyhhY2ZfcGVyaW9kKSwKIyAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcGN0X2NoYW5nZV9zbG9wZSkgJT4lCiMgICBtdXRhdGUocmF0aW9fYW5udWFsX3Nsb3BlID0gYGMuIHBvc3QtYWNmYCAvIGBhLiBwcmUtYWNmYCkKIyAgIAoKCgoKYGBgCgoKQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgZWZmZWN0IGFuZCBwb3N0IGVmZmVjdCBvZiBBQ0YKCmBgYHtyfQoKIyAKIyBsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfcG9zdF9kcmF3cykgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9cGN0X2NoYW5nZV9pbW1lZGlhdGUsIHk9cGN0X2NoYW5nZV9wb3N0LCBncm91cD13YXJkKSkgKwojICAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKIyAgIHN0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMCwgbGFiZWwueSA9IDAuMjUsIHNpemU9NCkgKwojICAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSIpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiMgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwojICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiMgICAgICAgIHk9IlBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdDogZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKIyAgICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIsCiMgICAgICAgIGNhcHRpb249IlBvaW50cyBhcmUgZHJhd3MgZnJvbSBwb3N0ZWlvciBkaXN0cmlidXRpb24iKSArCiMgICB0aGVtZV9nZ2Rpc3QoKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKIyAgIGZhY2V0X3dyYXAod2FyZH4uKQoKCmBgYAoKQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgZWZmZWN0IGFuZCBjaGFuZ2UgaW4gc2xvcGUKCmBgYHtyfQoKIyBsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfc2xvcGVfZHJhd3MpICU+JQojICAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSwgZ3JvdXA9d2FyZCkpICsKIyAgIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiMgICAjc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLCBsYWJlbC55ID0gMC4wMiwgc2l6ZT00KSArCiMgICBzY2FsZV9jb2xvdXJfc2NpY29fZChwYWxldHRlID0gImxpcGFyaSIsIG5hbWUgPSAiUG9zdGVyaW9yIHByb2JhYmlsaXR5IikgKwojICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKIyAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEwKSkgKwojICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiMgICAgICAgIHk9IlBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdDogUGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiMgICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAojICAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIGRyYXdzIGZyb20gcG9zdGVpb3IgZGlzdHJpYnV0aW9uIikgKwojICAgdGhlbWVfZ2dkaXN0KCkgKwojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiMgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiMgICBmYWNldF93cmFwKHdhcmR+LikKCgpgYGAKCgpKb2luIHRoZXNlIHRvZ2V0aGVyIHdpdGggdGhlIG92ZXJhbGwgZXN0aW1hdGVzIHRvIG1ha2UgYSBzaW5nbGUgZmlndXJlIGZvciBzaG93aW5nIGltcGFjdAoKYGBge3J9CgojIGYyX2RhdGEgPC0gCiMgICBsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfcG9zdF9kcmF3cykgJT4lCiMgICBsZWZ0X2pvaW4ob3ZlcmFsbF9zbG9wZV9kcmF3cykgJT4lCiMgICBtdXRhdGUobGV2ZWwgPSAib3ZlcmFsbCIsCiMgICAgICAgICAgd2FyZCA9ICJHbGFzZ293IikgJT4lCiMgICBiaW5kX3Jvd3MoCiMgICAgIGxlZnRfam9pbih3YXJkX2ltbWVkaWF0ZV9kcmF3cywgd2FyZF9wb3N0X2RyYXdzKSAlPiUKIyAgIGxlZnRfam9pbih3YXJkX3Nsb3BlX2RyYXdzKSAlPiUKIyAgIG11dGF0ZShsZXZlbCA9ICJ3YXJkIikKIyAgICkKIyAKIyBmMmEgPC0gZjJfZGF0YSAlPiUgCiMgICBnZ3Bsb3QoYWVzKHg9cGN0X2NoYW5nZV9pbW1lZGlhdGUsIHk9cGN0X2NoYW5nZV9wb3N0LCBncm91cD13YXJkKSkgKwojICAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKIyAgIHN0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMCwgbGFiZWwueSA9IDAuMTIsIHNpemU9NCkgKwojICAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSBkZW5zaXR5IikgKwojICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKIyAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiMgICBsYWJzKHk9IlBvc3QtaW50ZXJ2ZW50aW9uIGltcGFjdDogUGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiMgICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiKSArCiMgICB0aGVtZV9nZ2Rpc3QoKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKIyAgIGZhY2V0X3dyYXAoZmN0X3JlbGV2ZWwod2FyZCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIkdsYXNnb3ciLAojICAgICAgICAgICAgICAgICAgICAgICAgICBhZnRlcj0wKX4uLCBuY29sID0gNSkgKyAKIyAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKIyAKIyBmMmEKIyAKIyBmMmIgPC0gZjJfZGF0YSAlPiUgCiMgICBnZ3Bsb3QoYWVzKHg9cGN0X2NoYW5nZV9pbW1lZGlhdGUsIHk9cmF0aW9fYW5udWFsX3Nsb3BlLCBncm91cD13YXJkKSkgKwojICAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKIyAgIHN0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMS4yLCBsYWJlbC55ID0gMTIsIHNpemU9NCkgKwojICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiMgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNCkpICsKIyAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA0KSwKIyAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDE1KSkgKwojICAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJFIikgKwojICAgbGFicyh5PSJQb3N0LWludGVydmVudGlvbiBpbXBhY3Q6IFJlbGF0aXZlIGNoYW5nZSBpbiBhbm51YWwgQ05SIHNsb3BlICgxOTU4LTE5NjMgdnMuIDE5NTAtMTk1NikiLAojICAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKIyAgICAgICAgY29sb3VyPSJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgZGVuc2l0eSIpICsKIyAgIHRoZW1lX2dnZGlzdCgpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAojICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwojICAgZmFjZXRfd3JhcChmY3RfcmVsZXZlbCh3YXJkLAojICAgICAgICAgICAgICAgICAgICAgICAgICAiR2xhc2dvdyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgIGFmdGVyPTApfi4sIG5jb2wgPSA1KSArIAojICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQojIAojIGYyYgojIAojIChmMmEgLyBmMmIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMi5wbmciKSwgaGVpZ2h0PTE4LCB3aWR0aD0xMCkKCmBgYAoKIyMjIyA5LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKd2FyZF9jb3VudGVyZiA8LSBjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEyLCBtb2RlbD1tX3B1bG1vbmFyeV93YXJkLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQpCgp3YXJkX2NvdW50ZXJmICU+JQogIG1hcChkYXRhdGFibGUpCgoKYGBgCgpUb3RhbCBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKd2FyZF9hdmVydGVkIDwtIHdhcmRfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkLCBjYXNlc19hdmVydGVkLmxvd2VyLCBjYXNlc19hdmVydGVkLnVwcGVyKSwgc3VtKSwgLmJ5PXdhcmQpICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIH4gc2NhbGVzOjpudW1iZXIoeCA9IC4sIGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpICU+JQogIG11dGF0ZShjYXNlc19hdmVydGVkX3R4dCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfVxuKHtjYXNlc19hdmVydGVkLmxvd2VyfS17Y2FzZXNfYXZlcnRlZC51cHBlcn0pIikpICU+JQogIHNlbGVjdCh3YXJkLCBjYXNlc19hdmVydGVkX3R4dCkKCndhcmRfYXZlcnRlZCAlPiUgZGF0YXRhYmxlKCkKCmBgYAoKQWRkIHRoZSBudW1iZXJzIGF2ZXJ0ZWQgZm9yIGVhY2ggd2FyZCB0byB0aGUgZmlndXJlCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWw9bV9wdWxtb25hcnlfd2FyZCwgb3V0Y29tZSA9IGluY18xMDBrLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCkgKwogIGdlb21fdGV4dChkYXRhPXdhcmRfYXZlcnRlZCwgYWVzKHg9MTk2MSwgeT01MDAsIGxhYmVsPWNhc2VzX2F2ZXJ0ZWRfdHh0KSwgc2l6ZT0zKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNC5wbmciKSwgd2lkdGg9MTQsIGhlaWdodD0xMikKCgoKYGBgCgoKCgojIyMgMTAuIEFnZS1zZXggbW9kZWwKCiMjIyMgMTAuMSBGSXQgdGhlIG1vZGVsCgpGaXQgdGhlIG1vZGVsCgooTm90IHJld3JpdHRlbiB0aGUgZnVuY3Rpb25zIGZvciB0aGlzIHlldCkKCmBgYHtyfQoKbWRhdGEzIDwtIGNhc2VzX2J5X2FnZV9zZXggJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG11dGF0ZSh5X251bSA9IHJvd19udW1iZXIoKSkgJT4lCiAgdW5ncm91cCgpCgp3aW5mb3JtX3ByaW9yMyA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICAjcHJpb3IoZ2FtbWEoMC41LCAwLjAxKSwgY2xhc3MgPSBzaGFwZSksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpLAogICAgICAgICAgICAgICAgICBwcmlvcihsa2ooMiksIGNsYXNzPSJjb3IiKSkKCgptX2FnZV9zZXggPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyAoYWNmX3BlcmlvZCkqKGFnZSpzZXgpICsgKGFjZl9wZXJpb2Q6eV9udW0pKihhZ2Uqc2V4KSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gYmFzaWNfcHJpb3IsCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiKQoKc3VtbWFyeShtX2FnZV9zZXgpCnBsb3QobV9hZ2Vfc2V4KQpwcF9jaGVjayhtX2FnZV9zZXgsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgoKYGBgCgpTdW1tYXJpc2UgcG9zdGVyaW9yCgpgYGB7cn0KCiNwb3N0ZXJpb3IgZHJhd3MsIGFuZCBzdW1tYXJpc2UKYWdlX3NleF9zdW1tYXJ5IDwtIG1kYXRhMyAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCiNjcmVhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIChubyBpbnRlcnZlbnRpb24pLCBhbmQgc3VtbWFyaXNlCmFnZV9zZXhfY291bnRlcmZhY3QgPC0gCiAgdGliYmxlKHllYXIgPSBtZGF0YTMkeWVhciwKICAgICAgICAgeWVhcjIgPSBtZGF0YTMkeWVhcjIsCiAgICAgICAgIHlfbnVtID0gbWRhdGEzJHlfbnVtLAogICAgICAgICBhZ2UgPSBtZGF0YTMkYWdlLAogICAgICAgICBzZXggPSBtZGF0YTMkc2V4LAogICAgICAgICBhY2ZfcGVyaW9kID0gZmFjdG9yKCJhLiBwcmUtYWNmIikpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAKCgoKYWdlX3NleF9zdW1tYXJ5ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZ3JvdXAgPSBhY2ZfcGVyaW9kLCBmaWxsPWFjZl9wZXJpb2QpLCBhbHBoYT0wLjUpICsKICBnZW9tX3JpYmJvbihkYXRhID0gYWdlX3NleF9jb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeW1pbj0uZXByZWQubG93ZXIsIHltYXg9LmVwcmVkLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBjb2xvdXI9IkNvdW50ZXJmYWN0dWFsIikpICsKICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBncm91cD1hY2ZfcGVyaW9kLCAgY29sb3VyPWFjZl9wZXJpb2QpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWRhdGEzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAsIGFlcyh5PWNhc2VzLCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIGdnaDR4OjpmYWNldF9ncmlkMihhZ2V+c2V4LCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lPSIiKSArCiAgbGFicygKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9ucyAobikiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTQpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogIGd1aWRlcyhzaGFwZT0ibm9uZSIpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M3LnBuZyIpLCBoZWlnaHQ9MTApCgpgYGAKCiMjIyMgMTAuMiBTdW1tYXJ5IG9mIGltcGFjdCBvZiBpbnRlcnZlbnRpb24KCjEuIHBlcmNlbnRhZ2UgaW5jcmVhc2UgaW4gQ05SLCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKbmQgPC0gbWRhdGEzICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgeV9udW0sIGFnZSwgc2V4KQoKCmFnZV9zZXhfaW1wYWN0X291dCA8LSAKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgbmV3ZGF0YT1uZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCAuZXByZWQsIGFnZSwgc2V4KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWNmX3BlcmlvZCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IC5lcHJlZCwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBsaXN0KSAlPiUKICB1bm5lc3QoKSAlPiUKICByZW5hbWUocHJlX2VwcmVkID0gMywKICAgICAgICAgcG9zdF9lcHJlZCA9IDQpICU+JQogIG11dGF0ZShhY2ZfZGlmZiA9IHBvc3RfZXByZWQtcHJlX2VwcmVkLAogICAgICAgICBhY2ZfcnIgPSBwb3N0X2VwcmVkL3ByZV9lcHJlZCkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoYWNmX2RpZmYsIGFjZl9ycikgCgphZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgfiBzY2FsZXM6Om51bWJlcih4ID0gLiwgYWNjdXJhY3kgPSAwLjAxLCBiaWcubWFyayA9ICIsIikpICU+JQogIGRhdGF0YWJsZSgpCiAgCmYzYSA8LSBhZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX3JyLCB5bWluPWFjZl9yci5sb3dlciwgeW1heD1hY2ZfcnIudXBwZXIsIGdyb3VwPXNleCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjI1KSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBub3RpZmljYXRpb25zICg5NSUgVUkpXG5BQ0YgKDE5NTcpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKICAKICAKCmBgYAoKCjIuIENoYW5nZSBmcm9tIHByZS1BQ0YgcGVyaW9kICgxOTU2KSwgdG8gZmlyc3QgeWVhciBwb3N0LUFDRiAoMTk1OCkKCgpgYGB7cn0KCm5kIDwtIG1kYXRhMyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NiwxOTU4KSkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIHlfbnVtLCBhZ2UsIHNleCkKCiNEbyBpdCB3aXRoIGNhbGN1bGF0aW5nIGluY2lkZW5jZSwgdGhlbiBzdW1hbXJpc2luZy4KYWdlX3NleF9pbXBhY3QyIDwtYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCwKICAgICAgICAgICAgICAgIG5ld2RhdGE9bmQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgLmVwcmVkLCBhZ2UsIHNleCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFjZl9wZXJpb2QsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAuZXByZWQsCiAgICAgICAgICAgICAgdmFsdWVzX2ZuID0gbGlzdCkgJT4lCiAgdW5uZXN0KCkgJT4lCiAgcmVuYW1lKHByZV9lcHJlZCA9IDMsCiAgICAgICAgcG9zdF9lcHJlZCA9IDQpICU+JQogIG11dGF0ZShhY2ZfZGlmZiA9IHBvc3RfZXByZWQtcHJlX2VwcmVkLAogICAgICAgICBhY2ZfcnIgPSBwb3N0X2VwcmVkL3ByZV9lcHJlZCkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoYWNmX2RpZmYsIGFjZl9ycikgCgphZ2Vfc2V4X2ltcGFjdDIgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgfiBzY2FsZXM6Om51bWJlcih4ID0gLiwgYWNjdXJhY3kgPSAwLjAxLCBiaWcubWFyayA9ICIsIikpICU+JQogIGRhdGF0YWJsZSgpCgpmM2IgPC0gYWdlX3NleF9pbXBhY3QyICU+JSAgCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX3JyLCB5bWluPWFjZl9yci5sb3dlciwgeW1heD1hY2ZfcnIudXBwZXIsIGdyb3VwPXNleCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjI1KSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBub3RpZmljYXRpb25zICg5NSUgVUkpXG5BQ0YgKDE5NTgpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCjMuIENoYW5nZSBpbiBzbG9wZSAoaS5lLiBkaWZmZXJlbmNlIGluIG1lYW4gYW5udWFsIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcHJlLUludGVydmVudGlvbiB2cy4gcG9zdC1pbnRlcnZlbnRpb24sIGJ5IHdhcmQpCgpgYGB7cn0KCmFnZV9zZXhfaW1wYWN0MyA8LSBtZGF0YTMgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgY2FzZXMsIGFnZSwgc2V4KSAlPiUKICBmaWx0ZXIoeWVhciE9MTk1NykgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhciwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpICU+JQogIG1lYW5fcWkoLmVwcmVkKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG5feWVhcnMgPSBsZW5ndGgoeWVhciksIC5ieT1hY2ZfcGVyaW9kKSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9lcHJlZF9vdmVyYWxsID0gKCgobGFzdCguZXByZWQpIC0gZmlyc3QoLmVwcmVkKSkvZmlyc3QoLmVwcmVkKSkpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfdXBwZXJfb3ZlcmFsbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpKSwKICAgIAogICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoLmVwcmVkKSAtIGZpcnN0KC5lcHJlZCkpL2ZpcnN0KC5lcHJlZCkpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX2FubnVhbCA9ICgoKGxhc3QoLmxvd2VyKSAtIGZpcnN0KC5sb3dlcikpL2ZpcnN0KC5sb3dlcikpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX3VwcGVyX2FubnVhbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpL25feWVhcnMpLAogICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIGFnZSwgc2V4KSkgJT4lCiAgZGlzdGluY3QoKQoKCmFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCBwZXJjZW50KSAlPiUKICBkYXRhdGFibGUoKQoKZjNjIDwtIGFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0wKSwgbGluZXR5cGU9MikgKwogICAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PXBjdF9jaGFuZ2VfZXByZWRfYW5udWFsLCB5bWluPXBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsLCB5bWF4PXBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsLCBncm91cD1hY2ZfcGVyaW9kLCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX3BlcmlvZCksIHNpemU9MC4xKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9cGVyY2VudCkgKwogIGZhY2V0X2dyaWQoLn5zZXgpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICIjNEQ2Q0ZBIikpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJNZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICg5NSUgVUkpXG4gQmVmb3JlIEFDRiAoMTk1MC0xOTU2KSB2cy4gYWZ0ZXIgQUNGICgxOTU4LTE5NjMpIiwKICAgICAgIGNvbG91cj0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZjNjCgpgYGAKCgojIyMjIDEwLjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKY291bnRlcmZhY3RfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhMyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkX2NvdW50ZXJmID0gLmVwcmVkKQogIAojQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KICBwb3N0X2NoYW5nZV9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEzICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCwgYWNmX3BlcmlvZCkpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwgYWdlLCBzZXgsIC5kcmF3LCAuZXByZWQpIAogIAogICNmb3IgdGhlIG92ZXJhbGwgcGVyaW9kCmNvdW50ZXJmYWN0X292ZXJhbGxfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhMyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KGFnZSwgc2V4LCAuZHJhdykgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWRfY291bnRlcmYgPSBzdW0oLmVwcmVkKSkgJT4lCiAgICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKQogIAogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlX292ZXJhbGxfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhMyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCBhZ2UsIHNleCkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCiAgCgpsZWZ0X2pvaW4oY291bnRlcmZhY3RfYWdlX3NleCwgcG9zdF9jaGFuZ2VfYWdlX3NleCkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGNhc2VzX2F2ZXJ0ZWQsIHBjdF9jaGFuZ2UpICU+JQogICAgdW5ncm91cCgpICU+JQogIGRhdGF0YWJsZSgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0X292ZXJhbGxfYWdlX3NleCwgcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4KSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoeWVhciA9ICJPdmVyYWxsICgxOTU4LTE5NjMpIikgCgoKYGBgCgoKYGBge3J9CgphZ2Vfc2V4X3R4dCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgdHJhbnNtdXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIHNleCA9IHNleCwKICAgICAgICAgICAgYWdlID0gYWdlLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9XG4oe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfVxuKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCgoKYWdlX3NleF90eHQgJT4lIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmYzZCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JSAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeCA9IGFnZSwgeT1jYXNlc19hdmVydGVkLCB5bWluPWNhc2VzX2F2ZXJ0ZWQubG93ZXIsIHltYXg9Y2FzZXNfYXZlcnRlZC51cHBlciwgY29sb3VyPXNleCkpICsgCiAgZmFjZXRfZ3JpZCgufnNleCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iTnVtYmVyICg5NSUgVUkpIG9mIFRCIGNhc2VzIGF2ZXJ0ZWQgKDE5NTgtMTk2MykiLAogICAgICAgY29sb3VyPSIiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZjNkCmBgYAoKCgoKSm9pbiB0b2dldGhlciBmb3IgRmlndXJlIDIuCgoKYGBge3J9CgooZjNhICsgZjNiKSAvIChmM2MgKyBmM2QpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMy5wbmciKSwgd2lkdGggPSAxMikKCgpgYGAKCgojIyMgMTEuIERpdmlzaW9uLWxldmVsIG1vZGVsCgooVmVyeSBtdWNoIGEgd29yayBpbiBwcm9ncmVzcyEpCgpgYGB7cn0KCm1kYXRhNCA8LSBkaXZpc2lvbl9pbmMgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieShkaXZpc2lvbikgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCmBgYAoKYGBge3J9CmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDAsIHRvID0gMTUwMCwgYnkgPSAxMCkpLAogICAgICAgYWVzKHggPSB4LCB5ID0gZGdhbW1hKHgsIHNoYXBlID0gMiwgcmF0ZSA9IDAuMDAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgc2NhbGVfeV9jb250aW51b3VzKE5VTEwsIGJyZWFrcyA9IE5VTEwpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMTUwMCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMC41KiIsICIqMC4wMDAxKX5zaGFwZX5wcmlvcikpCgp3aW5mb3JtX3ByaW9yMyA8LSBjKHByaW9yKG5vcm1hbCgwLCAwLjEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDIsIDAuMDAwMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMDAxKSwgY2xhc3MgPSBiLCBjb2VmID0gImFjZl9wZXJpb2RiLmFjZiIpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMDAxKSwgY2xhc3MgPSBiLCBjb2VmID0gImFjZl9wZXJpb2RjLnBvc3RNYWNmIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMDEpLCBjbGFzcyA9IGIsIGNvZWYgPSAieV9udW0iKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAwMSksIGNsYXNzID0gYiwgY29lZiA9ICJ5X251bTphY2ZfcGVyaW9kYi5hY2YiKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAwMSksIGNsYXNzID0gYiwgY29lZiA9ICJ5X251bTphY2ZfcGVyaW9kYy5wb3N0TWFjZiIpLAogICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIikpCgoKbV9wdWxtb25hcnlfZGl2aXNpb25fcHJpb3IgPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICgxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSB8IGRpdmlzaW9uICkgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhNCwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvcjMsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOSkpCgpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X2RpdmlzaW9uX3ByaW9yKQpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsPW1fcHVsbW9uYXJ5X2RpdmlzaW9uX3ByaW9yLCBtb2RlbF9kYXRhPW1kYXRhNCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG91dGNvbWUgPSBpbmNfMTAwaywgZ3JvdXBpbmdfdmFyID0gZGl2aXNpb24sIGRpdmlzaW9uKQoKCmBgYAoKCgpgYGB7cn0KCm1fcHVsbW9uYXJ5X2RpdmlzaW9uIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCBkaXZpc2lvbikgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhNCwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvcjMsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDAsCiAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjkpKQoKc3VtbWFyeShtX3B1bG1vbmFyeV9kaXZpc2lvbikKcGxvdChtX3B1bG1vbmFyeV9kaXZpc2lvbikKcHBfY2hlY2sobV9wdWxtb25hcnlfZGl2aXNpb24sIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsPW1fcHVsbW9uYXJ5X2RpdmlzaW9uLCBtb2RlbF9kYXRhPW1kYXRhNCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG91dGNvbWUgPSBpbmNfMTAwaywgZ3JvdXBpbmdfdmFyID0gZGl2aXNpb24sIGRpdmlzaW9uKQoKCmBgYAoKIyMjIyAxMC4yIFN1bW1hcnkgb2YgaW1wYWN0CgoKYGBge3J9CgpzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9bWRhdGE0LCBtb2RlbCA9IG1fcHVsbW9uYXJ5X2RpdmlzaW9uLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gZGl2aXNpb24pICU+JQogIG1hcChkYXRhdGFibGUpCgoKYGBgCgoKCiMjIyAxMi4gQ291bnRlcmZhY3R1YWwgdGFibGUKCk1ha2UgYSB0YWJsZSBvZiBjb3VudGVyZmFjdHVhbCBlZmZlY3RzIGZvciB0aGUgbWFudXNjcmlwdAoKYGBge3J9CgpwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzKG92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdCkKcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwob3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwpCgpleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHMgPC0gdGlkeV9jb3VudGVyZmFjdHVhbHMob3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3QpCmV4dHJhcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwob3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCkKCmFnZV9zZXhfY291bnRlcmZhY3R1YWxzX292ZXJhbGwgPC0gdGlkeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbChjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4KSAlPiUgbXV0YXRlKG1vZGVsID0gIkFnZS1zZXgiKQoKYmluZF9yb3dzKAogIGJpbmRfcm93cyhwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzLCBwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwpICU+JSBtdXRhdGUobW9kZWwgPSAiUHVsbW9uYXJ5IFRCIiwgc2V4PU5BLCBhZ2U9TkEpLAogIGJpbmRfcm93cyhleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHMsIGV4dHJhcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gIkV4dHJhLXB1bG1vbmFyeSBUQiIsIHNleD1OQSwgYWdlPU5BKSwKICBhZ2Vfc2V4X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKSAlPiUKICBzZWxlY3QobW9kZWwsIHllYXIsIGFnZSwgc2V4LCBkaWZmX2luYywgcnJfaW5jLCBjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKQoKCgpgYGAKCgoKIyMjIyMjIyMjIyMjIyMKI2V4cGVyaW1lbnRhbCBiZWxvdyBoZXJlCiMjIyMjIyMjIyMjIyMKCgpXaGF0IGFib3V0IGEgbXVsdGlsZXZlbCBtb2RlbCB3aXRoIFdhcmRzIG5lc3RlZCB3aXRoaW4gZGl2aXNpb25zPwoKYGBge3J9CgptZGF0YTQgPC0gd2FyZF9pbmMgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKCgpgYGAKCmBgYHtyfQoKd2luZm9ybV9wcmlvcjQgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgI3ByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpLAogICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9ImNvciIpKQpgYGAKCgpgYGB7cn0KCm1fcHVsbW9uYXJ5X25lc3RlZCA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgKyB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtIHwgZGl2aXNpb24vd2FyZCksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3I0LAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKc3VtbWFyeShtX3B1bG1vbmFyeV9uZXN0ZWQpCmNvbmRpdGlvbmFsX2VmZmVjdHMobV9wdWxtb25hcnlfbmVzdGVkKQoKCmBgYAo=